new ethernet drivers with multicast and shutdown entry points; not all have been tested. multicast is needed for ipv6 and shutdown is needed for /dev/reboot. Reference: /n/sources/patch/applied/ether-multicast-shutdown Date: Sat Apr 17 18:59:35 CES 2004 --- /sys/src/9/pc/ether2114x.c Sat Apr 17 18:59:30 2004 +++ /sys/src/9/pc/ether2114x.c Sat Apr 17 18:59:30 2004 @@ -284,6 +284,12 @@ iunlock(&ctlr->lock); } +/* multicast already on, don't need to do anything */ +static void +multicast(void*, uchar*, int) +{ +} + static void attach(Ether* ether) { @@ -603,7 +609,7 @@ ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti; csr32w(ctlr, 5, ctlr->mask); csr32w(ctlr, 7, ctlr->mask); - ctlr->csr6 |= St; + ctlr->csr6 |= St|Pm; csr32w(ctlr, 6, ctlr->csr6); for(i = 0; i < Eaddrlen/2; i++){ @@ -800,6 +806,15 @@ } static void +shutdown(Ether* ether) +{ + Ctlr *ctlr = ether->ctlr; + +print("ether2114x shutting down\n"); + csr32w(ctlr, 0, Swr); +} + +static void softreset(Ctlr* ctlr) { /* @@ -1798,6 +1813,8 @@ ether->ifstat = ifstat; ether->arg = ether; + ether->shutdown = shutdown; + ether->multicast = multicast; ether->promiscuous = promiscuous; return 0; --- /sys/src/9/pc/ether83815.c Sat Apr 17 18:59:32 2004 +++ /sys/src/9/pc/ether83815.c Sat Apr 17 18:59:32 2004 @@ -598,9 +598,13 @@ * unmask interrupts and start the transmit side */ ctlr->rdr = malloc(ctlr->nrdr*sizeof(Des)); + if (ctlr->rdr == nil) + error(Enomem); last = nil; for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){ des->bp = iallocb(Rbsz); + if (des->bp == nil) + error(Enomem); des->cmdsts = Rbsz; des->addr = PADDR(des->bp->rp); if(last != nil) @@ -659,19 +663,21 @@ static int eegetw(Ctlr *ctlr, int a) { - int d, i, w, v; + int d, i, w; eeidle(ctlr); eeclk(ctlr, 0); eeclk(ctlr, Eeclk); d = 0x180 | a; for(i=0x400; i; i>>=1){ - v = (d & i) ? Eedi : 0; - eeclk(ctlr, v); - eeclk(ctlr, Eeclk|v); + if(d & i) + csr32w(ctlr, Rmear, Eesel|Eedi); + else + csr32w(ctlr, Rmear, Eesel); + eeclk(ctlr, Eeclk); + eeclk(ctlr, 0); + microdelay(2); } - eeclk(ctlr, 0); - w = 0; for(i=0x8000; i; i >>= 1){ eeclk(ctlr, Eeclk); @@ -685,13 +691,10 @@ } static void -softreset(Ctlr* ctlr, int resetphys) +resetctlr(Ctlr *ctlr) { - int i, w; + int i; - /* - * Soft-reset the controller - */ csr32w(ctlr, Rcr, Rst); for(i=0;; i++){ if(i > 100) @@ -701,7 +704,27 @@ break; delay(1); } +} +static void +shutdown(Ether* ether) +{ + Ctlr *ctlr = ether->ctlr; + +print("ether83815 shutting down\n"); + csr32w(ctlr, Rcr, Rxd|Txd); /* disable transceiver */ + resetctlr(ctlr); +} + +static void +softreset(Ctlr* ctlr, int resetphys) +{ + int i, w; + + /* + * Soft-reset the controller + */ + resetctlr(ctlr); csr32w(ctlr, Rccsr, Pmests); csr32w(ctlr, Rccsr, 0); csr32w(ctlr, Rcfg, csr32r(ctlr, Rcfg) | Pint_acen); @@ -953,11 +976,11 @@ ether->transmit = transmit; ether->interrupt = interrupt; ether->ifstat = ifstat; - ether->multicast = multicast; ether->arg = ether; ether->promiscuous = promiscuous; - + ether->multicast = multicast; + ether->shutdown = shutdown; return 0; } --- /sys/src/9/pc/etherdp83820.c Thu Jan 1 00:00:00 1970 +++ /sys/src/9/pc/etherdp83820.c Sat Apr 17 18:59:32 2004 @@ -0,0 +1,1302 @@ +/* + * National Semiconductor DP83820 & DP83821 + * 10/100/1000 Mb/s Ethernet Network Interface Controller + * (Gig-NIC). + * Driver assumes little-endian and 32-bit host throughout. + */ +#ifdef FS +#include "all.h" +#include "io.h" +#include "mem.h" +#include "../ip/ip.h" + +#else + +#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" +#endif /* FS */ + +#include "etherif.h" +#include "ethermii.h" + +#include "compat.h" + +enum { /* Registers */ + Cr = 0x00, /* Command */ + Cfg = 0x04, /* Configuration and Media Status */ + Mear = 0x08, /* MII/EEPROM Access */ + Ptscr = 0x0C, /* PCI Test Control */ + Isr = 0x10, /* Interrupt Status */ + Imr = 0x14, /* Interrupt Mask */ + Ier = 0x18, /* Interrupt Enable */ + Ihr = 0x1C, /* Interrupt Holdoff */ + Txdp = 0x20, /* Transmit Descriptor Pointer */ + Txdphi = 0x24, /* Transmit Descriptor Pointer Hi */ + Txcfg = 0x28, /* Transmit Configuration */ + Gpior = 0x2C, /* General Purpose I/O Control */ + Rxdp = 0x30, /* Receive Descriptor Pointer */ + Rxdphi = 0x34, /* Receive Descriptor Pointer Hi */ + Rxcfg = 0x38, /* Receive Configuration */ + Pqcr = 0x3C, /* Priority Queueing Control */ + Wcsr = 0x40, /* Wake on LAN Control/Status */ + Pcr = 0x44, /* Pause Control/Status */ + Rfcr = 0x48, /* Receive Filter/Match Control */ + Rfdr = 0x4C, /* Receive Filter/Match Data */ + Brar = 0x50, /* Boot ROM Address */ + Brdr = 0x54, /* Boot ROM Data */ + Srr = 0x58, /* Silicon Revision */ + Mibc = 0x5C, /* MIB Control */ + Mibd = 0x60, /* MIB Data */ + Txdp1 = 0xA0, /* Txdp Priority 1 */ + Txdp2 = 0xA4, /* Txdp Priority 2 */ + Txdp3 = 0xA8, /* Txdp Priority 3 */ + Rxdp1 = 0xB0, /* Rxdp Priority 1 */ + Rxdp2 = 0xB4, /* Rxdp Priority 2 */ + Rxdp3 = 0xB8, /* Rxdp Priority 3 */ + Vrcr = 0xBC, /* VLAN/IP Receive Control */ + Vtcr = 0xC0, /* VLAN/IP Transmit Control */ + Vdr = 0xC4, /* VLAN Data */ + Ccsr = 0xCC, /* Clockrun Control/Status */ + Tbicr = 0xE0, /* TBI Control */ + Tbisr = 0xE4, /* TBI Status */ + Tanar = 0xE8, /* TBI ANAR */ + Tanlpar = 0xEC, /* TBI ANLPAR */ + Taner = 0xF0, /* TBI ANER */ + Tesr = 0xF4, /* TBI ESR */ +}; + +enum { /* Cr */ + Txe = 0x00000001, /* Transmit Enable */ + Txd = 0x00000002, /* Transmit Disable */ + Rxe = 0x00000004, /* Receiver Enable */ + Rxd = 0x00000008, /* Receiver Disable */ + Txr = 0x00000010, /* Transmitter Reset */ + Rxr = 0x00000020, /* Receiver Reset */ + Swien = 0x00000080, /* Software Interrupt Enable */ + Rst = 0x00000100, /* Reset */ + TxpriSHFT = 9, /* Tx Priority Queue Select */ + TxpriMASK = 0x00001E00, + RxpriSHFT = 13, /* Rx Priority Queue Select */ + RxpriMASK = 0x0001E000, +}; + +enum { /* Configuration and Media Status */ + Bem = 0x00000001, /* Big Endian Mode */ + Ext125 = 0x00000002, /* External 125MHz reference Select */ + Bromdis = 0x00000004, /* Disable Boot ROM interface */ + Pesel = 0x00000008, /* Parity Error Detection Action */ + Exd = 0x00000010, /* Excessive Deferral Abort */ + Pow = 0x00000020, /* Program Out of Window Timer */ + Sb = 0x00000040, /* Single Back-off */ + Reqalg = 0x00000080, /* PCI Bus Request Algorithm */ + Extstsen = 0x00000100, /* Extended Status Enable */ + Phydis = 0x00000200, /* Disable PHY */ + Phyrst = 0x00000400, /* Reset PHY */ + M64addren = 0x00000800, /* Master 64-bit Addressing Enable */ + Data64en = 0x00001000, /* 64-bit Data Enable */ + Pci64det = 0x00002000, /* PCI 64-bit Bus Detected */ + T64addren = 0x00004000, /* Target 64-bit Addressing Enable */ + Mwidis = 0x00008000, /* MWI Disable */ + Mrmdis = 0x00010000, /* MRM Disable */ + Tmrtest = 0x00020000, /* Timer Test Mode */ + Spdstsien = 0x00040000, /* PHY Spdsts Interrupt Enable */ + Lnkstsien = 0x00080000, /* PHY Lnksts Interrupt Enable */ + Dupstsien = 0x00100000, /* PHY Dupsts Interrupt Enable */ + Mode1000 = 0x00400000, /* 1000Mb/s Mode Control */ + Tbien = 0x01000000, /* Ten-Bit Interface Enable */ + Dupsts = 0x10000000, /* Full Duplex Status */ + Spdsts100 = 0x20000000, /* SPEED100 Input Pin Status */ + Spdsts1000 = 0x40000000, /* SPEED1000 Input Pin Status */ + Lnksts = 0x80000000, /* Link Status */ +}; + +enum { /* MII/EEPROM Access */ + Eedi = 0x00000001, /* EEPROM Data In */ + Eedo = 0x00000002, /* EEPROM Data Out */ + Eeclk = 0x00000004, /* EEPROM Serial Clock */ + Eesel = 0x00000008, /* EEPROM Chip Select */ + Mdio = 0x00000010, /* MII Management Data */ + Mddir = 0x00000020, /* MII Management Direction */ + Mdc = 0x00000040, /* MII Management Clock */ +}; + +enum { /* Interrupts */ + Rxok = 0x00000001, /* Rx OK */ + Rxdesc = 0x00000002, /* Rx Descriptor */ + Rxerr = 0x00000004, /* Rx Packet Error */ + Rxearly = 0x00000008, /* Rx Early Threshold */ + Rxidle = 0x00000010, /* Rx Idle */ + Rxorn = 0x00000020, /* Rx Overrun */ + Txok = 0x00000040, /* Tx Packet OK */ + Txdesc = 0x00000080, /* Tx Descriptor */ + Txerr = 0x00000100, /* Tx Packet Error */ + Txidle = 0x00000200, /* Tx Idle */ + Txurn = 0x00000400, /* Tx Underrun */ + Mib = 0x00000800, /* MIB Service */ + Swi = 0x00001000, /* Software Interrupt */ + Pme = 0x00002000, /* Power Management Event */ + Phy = 0x00004000, /* PHY Interrupt */ + Hibint = 0x00008000, /* High Bits Interrupt Set */ + Rxsovr = 0x00010000, /* Rx Status FIFO Overrun */ + Rtabt = 0x00020000, /* Received Target Abort */ + Rmabt = 0x00040000, /* Received Master Abort */ + Sserr = 0x00080000, /* Signalled System Error */ + Dperr = 0x00100000, /* Detected Parity Error */ + Rxrcmp = 0x00200000, /* Receive Reset Complete */ + Txrcmp = 0x00400000, /* Transmit Reset Complete */ + Rxdesc0 = 0x00800000, /* Rx Descriptor for Priority Queue 0 */ + Rxdesc1 = 0x01000000, /* Rx Descriptor for Priority Queue 1 */ + Rxdesc2 = 0x02000000, /* Rx Descriptor for Priority Queue 2 */ + Rxdesc3 = 0x04000000, /* Rx Descriptor for Priority Queue 3 */ + Txdesc0 = 0x08000000, /* Tx Descriptor for Priority Queue 0 */ + Txdesc1 = 0x10000000, /* Tx Descriptor for Priority Queue 1 */ + Txdesc2 = 0x20000000, /* Tx Descriptor for Priority Queue 2 */ + Txdesc3 = 0x40000000, /* Tx Descriptor for Priority Queue 3 */ +}; + +enum { /* Interrupt Enable */ + Ien = 0x00000001, /* Interrupt Enable */ +}; + +enum { /* Interrupt Holdoff */ + IhSHFT = 0, /* Interrupt Holdoff */ + IhMASK = 0x000000FF, + Ihctl = 0x00000100, /* Interrupt Holdoff Control */ +}; + +enum { /* Transmit Configuration */ + TxdrthSHFT = 0, /* Tx Drain Threshold */ + TxdrthMASK = 0x000000FF, + FlthSHFT = 16, /* Tx Fill Threshold */ + FlthMASK = 0x0000FF00, + Brstdis = 0x00080000, /* 1000Mb/s Burst Disable */ + MxdmaSHFT = 20, /* Max Size per Tx DMA Burst */ + MxdmaMASK = 0x00700000, + Ecretryen = 0x00800000, /* Excessive Collision Retry Enable */ + Atp = 0x10000000, /* Automatic Transmit Padding */ + Mlb = 0x20000000, /* MAC Loopback */ + Hbi = 0x40000000, /* Heartbeat Ignore */ + Csi = 0x80000000, /* Carrier Sense Ignore */ +}; + +enum { /* Receive Configuration */ + RxdrthSHFT = 1, /* Rx Drain Threshold */ + RxdrthMASK = 0x0000003E, + Airl = 0x04000000, /* Accept In-Range Length Errored */ + Alp = 0x08000000, /* Accept Long Packets */ + Rxfd = 0x10000000, /* Receive Full Duplex */ + Stripcrc = 0x20000000, /* Strip CRC */ + Arp = 0x40000000, /* Accept Runt Packets */ + Aep = 0x80000000, /* Accept Errored Packets */ +}; + +enum { /* Priority Queueing Control */ + Txpqen = 0x00000001, /* Transmit Priority Queuing Enable */ + Txfairen = 0x00000002, /* Transmit Fairness Enable */ + RxpqenSHFT = 2, /* Receive Priority Queue Enable */ + RxpqenMASK = 0x0000000C, +}; + +enum { /* Pause Control/Status */ + PscntSHFT = 0, /* Pause Counter Value */ + PscntMASK = 0x0000FFFF, + Pstx = 0x00020000, /* Transmit Pause Frame */ + PsffloSHFT = 18, /* Rx Data FIFO Lo Threshold */ + PsffloMASK = 0x000C0000, + PsffhiSHFT = 20, /* Rx Data FIFO Hi Threshold */ + PsffhiMASK = 0x00300000, + PsstloSHFT = 22, /* Rx Stat FIFO Hi Threshold */ + PsstloMASK = 0x00C00000, + PssthiSHFT = 24, /* Rx Stat FIFO Hi Threshold */ + PssthiMASK = 0x03000000, + Psrcvd = 0x08000000, /* Pause Frame Received */ + Psact = 0x10000000, /* Pause Active */ + Psda = 0x20000000, /* Pause on Destination Address */ + Psmcast = 0x40000000, /* Pause on Multicast */ + Psen = 0x80000000, /* Pause Enable */ +}; + +enum { /* Receive Filter/Match Control */ + RfaddrSHFT = 0, /* Extended Register Address */ + RfaddrMASK = 0x000003FF, + Ulm = 0x00080000, /* U/L bit mask */ + Uhen = 0x00100000, /* Unicast Hash Enable */ + Mhen = 0x00200000, /* Multicast Hash Enable */ + Aarp = 0x00400000, /* Accept ARP Packets */ + ApatSHFT = 23, /* Accept on Pattern Match */ + ApatMASK = 0x07800000, + Apm = 0x08000000, /* Accept on Perfect Match */ + Aau = 0x10000000, /* Accept All Unicast */ + Aam = 0x20000000, /* Accept All Multicast */ + Aab = 0x40000000, /* Accept All Broadcast */ + Rfen = 0x80000000, /* Rx Filter Enable */ +}; + +enum { /* Receive Filter/Match Data */ + RfdataSHFT = 0, /* Receive Filter Data */ + RfdataMASK = 0x0000FFFF, + BmaskSHFT = 16, /* Byte Mask */ + BmaskMASK = 0x00030000, +}; + +enum { /* MIB Control */ + Wrn = 0x00000001, /* Warning Test Indicator */ + Frz = 0x00000002, /* Freeze All Counters */ + Aclr = 0x00000004, /* Clear All Counters */ + Mibs = 0x00000008, /* MIB Counter Strobe */ +}; + +enum { /* MIB Data */ + Nmibd = 11, /* Number of MIB Data Registers */ +}; + +enum { /* VLAN/IP Receive Control */ + Vtden = 0x00000001, /* VLAN Tag Detection Enable */ + Vtren = 0x00000002, /* VLAN Tag Removal Enable */ + Dvtf = 0x00000004, /* Discard VLAN Tagged Frames */ + Dutf = 0x00000008, /* Discard Untagged Frames */ + Ipen = 0x00000010, /* IP Checksum Enable */ + Ripe = 0x00000020, /* Reject IP Checksum Errors */ + Rtcpe = 0x00000040, /* Reject TCP Checksum Errors */ + Rudpe = 0x00000080, /* Reject UDP Checksum Errors */ +}; + +enum { /* VLAN/IP Transmit Control */ + Vgti = 0x00000001, /* VLAN Global Tag Insertion */ + Vppti = 0x00000002, /* VLAN Per-Packet Tag Insertion */ + Gchk = 0x00000004, /* Global Checksum Generation */ + Ppchk = 0x00000008, /* Per-Packet Checksum Generation */ +}; + +enum { /* VLAN Data */ + VtypeSHFT = 0, /* VLAN Type Field */ + VtypeMASK = 0x0000FFFF, + VtciSHFT = 16, /* VLAN Tag Control Information */ + VtciMASK = 0xFFFF0000, +}; + +enum { /* Clockrun Control/Status */ + Clkrunen = 0x00000001, /* CLKRUN Enable */ + Pmeen = 0x00000100, /* PME Enable */ + Pmests = 0x00008000, /* PME Status */ +}; + +typedef struct { + u32int link; /* Link to the next descriptor */ + u32int bufptr; /* pointer to data Buffer */ + int cmdsts; /* Command/Status */ + int extsts; /* optional Extended Status */ + + Block* bp; /* Block containing bufptr */ + u32int unused; /* pad to 64-bit */ +} Desc; + +enum { /* Common cmdsts bits */ + SizeMASK = 0x0000FFFF, /* Descriptor Byte Count */ + SizeSHFT = 0, + Ok = 0x08000000, /* Packet OK */ + Crc = 0x10000000, /* Suppress/Include CRC */ + Intr = 0x20000000, /* Interrupt on ownership transfer */ + More = 0x40000000, /* not last descriptor in a packet */ + Own = 0x80000000, /* Descriptor Ownership */ +}; + +enum { /* Transmit cmdsts bits */ + CcntMASK = 0x000F0000, /* Collision Count */ + CcntSHFT = 16, + Ec = 0x00100000, /* Excessive Collisions */ + Owc = 0x00200000, /* Out of Window Collision */ + Ed = 0x00400000, /* Excessive Deferral */ + Td = 0x00800000, /* Transmit Deferred */ + Crs = 0x01000000, /* Carrier Sense Lost */ + Tfu = 0x02000000, /* Transmit FIFO Underrun */ + Txa = 0x04000000, /* Transmit Abort */ +}; + +enum { /* Receive cmdsts bits */ + Irl = 0x00010000, /* In-Range Length Error */ + Lbp = 0x00020000, /* Loopback Packet */ + Fae = 0x00040000, /* Frame Alignment Error */ + Crce = 0x00080000, /* CRC Error */ + Ise = 0x00100000, /* Invalid Symbol Error */ + Runt = 0x00200000, /* Runt Packet Received */ + Long = 0x00400000, /* Too Long Packet Received */ + DestMASK = 0x01800000, /* Destination Class */ + DestSHFT = 23, + Rxo = 0x02000000, /* Receive Overrun */ + Rxa = 0x04000000, /* Receive Aborted */ +}; + +enum { /* extsts bits */ + EvtciMASK = 0x0000FFFF, /* VLAN Tag Control Information */ + EvtciSHFT = 0, + Vpkt = 0x00010000, /* VLAN Packet */ + /* Ippkt, Udppkt are struct types in the fs kernel */ + Ippacket = 0x00020000, /* IP Packet */ + Iperr = 0x00040000, /* IP Checksum Error */ + Tcppkt = 0x00080000, /* TCP Packet */ + Tcperr = 0x00100000, /* TCP Checksum Error */ + Udppacket = 0x00200000, /* UDP Packet */ + Udperr = 0x00400000, /* UDP Checksum Error */ +}; + +/* + * adjust these, keeping in mind that at 1Gb/s, a 1514-byte packet is + * sent or received in 12µs. Ignoring mandatory inter-packet gaps, + * a ring of 32 buffers will take 388µs to fill or empty; 64 buffers + * will take 775µs; 256 will take 3.1ms. + */ +enum { + Nrd = 64, // was 64 then 450 + Nrb = 4*Nrd, + Rbsz = ROUNDUP(sizeof(Etherpkt)+8, 8), + Ntd = Nrd, // was 32 then 450 +}; + +typedef struct Ctlr Ctlr; +typedef struct Ctlr { + int port; + Pcidev* pcidev; + Ctlr* next; + int active; + int id; + + int eepromsz; /* address size in bits */ + ushort* eeprom; + + int* nic; + int cfg; + int imr; + + QLock alock; /* attach */ + Lock ilock; /* init */ + void* alloc; /* base of per-Ctlr allocated data */ + + Mii* mii; + + Lock rdlock; /* receive */ + Desc* rd; + int nrd; + int nrb; + int rdx; + int rxcfg; + + Lock tlock; /* transmit */ + Desc* td; + int ntd; + int tdh; + int tdt; + int ntq; + int txcfg; + + int rxidle; + + uint mibd[Nmibd]; + + int ec; + int owc; + int ed; + int crs; + int tfu; + int txa; +} Ctlr; + +#define csr32r(c, r) (*((c)->nic+((r)/4))) +#define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v)) + +static Ctlr* dp83820ctlrhead; +static Ctlr* dp83820ctlrtail; + +static Lock dp83820rblock; /* free receive Blocks */ +static Block* dp83820rbpool; + +static char* dp83820mibs[Nmibd] = { + "RXErroredPkts", + "RXFCSErrors", + "RXMsdPktErrors", + "RXFAErrors", + "RXSymbolErrors", + "RXFrameToLong", + "RXIRLErrors", + "RXBadOpcodes", + "RXPauseFrames", + "TXPauseFrames", + "TXSQEErrors", +}; + +static int +mdior(Ctlr* ctlr, int n) +{ + int data, i, mear, r; + + mear = csr32r(ctlr, Mear); + r = ~(Mdc|Mddir) & mear; + data = 0; + for(i = n-1; i >= 0; i--){ + if(csr32r(ctlr, Mear) & Mdio) + data |= (1<= 0; i--){ + if(bits & (1<ctlr; + + /* + * MII Management Interface Read. + * + * Preamble; + * ST+OP+PA+RA; + * LT + 16 data bits. + */ + mdiow(ctlr, 0xFFFFFFFF, 32); + mdiow(ctlr, 0x1800|(pa<<5)|ra, 14); + data = mdior(ctlr, 18); + + if(data & 0x10000) + return -1; + + return data & 0xFFFF; +} + +static int +dp83820miimiw(Mii* mii, int pa, int ra, int data) +{ + Ctlr *ctlr; + + ctlr = mii->ctlr; + + /* + * MII Management Interface Write. + * + * Preamble; + * ST+OP+PA+RA+LT + 16 data bits; + * Z. + */ + mdiow(ctlr, 0xFFFFFFFF, 32); + data &= 0xFFFF; + data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16); + mdiow(ctlr, data, 32); + return data & 0xFFFF; /* TODO: what's the caller expect here? */ +} + +/* + * return free Block+buffer ready for input of up to MTU bytes. + * desc->bp is also set to the return value. + */ +static Block * +dp83820rballoc(Desc* desc) +{ + Block *bp; + + if(desc->bp == nil){ + ilock(&dp83820rblock); + if((bp = dp83820rbpool) == nil){ + iunlock(&dp83820rblock); + desc->bp = nil; + desc->cmdsts = Own; + iprint("dp83820rballoc: out of buffers\n"); + return nil; + } + dp83820rbpool = bp->next; + bp->next = nil; + iunlock(&dp83820rblock); + + desc->bufptr = PCIWADDR(bp->rp); + desc->bp = bp; + } + else{ + bp = desc->bp; + BLKRESET(bp); + } + + coherence(); + desc->cmdsts = Intr|Rbsz; + return bp; +} + +/* should be called via freeb() */ +static void +dp83820rbfree(Block *bp) +{ + BLKRESET(bp); + + ilock(&dp83820rblock); + bp->next = dp83820rbpool; + dp83820rbpool = bp; + iunlock(&dp83820rblock); +} + +static void +dp83820halt(Ctlr* ctlr) +{ + int i; + + ilock(&ctlr->ilock); + csr32w(ctlr, Imr, 0); + csr32w(ctlr, Ier, 0); + csr32w(ctlr, Cr, Rxd|Txd); + /* TODO: limit this; don't wait forever with a lock held */ + while(csr32r(ctlr, Cr) & (Rxe|Txe)) + ; + csr32w(ctlr, Mibc, Frz); + iunlock(&ctlr->ilock); + + if(ctlr->rd != nil){ + for(i = 0; i < ctlr->nrd; i++){ + if(ctlr->rd[i].bp == nil) + continue; + freeb(ctlr->rd[i].bp); + ctlr->rd[i].bp = nil; + } + } + if(ctlr->td != nil){ + for(i = 0; i < ctlr->ntd; i++){ + if(ctlr->td[i].bp == nil) + continue; + freeb(ctlr->td[i].bp); + ctlr->td[i].bp = nil; + } + } +} + +static void +dp83820cfg(Ctlr* ctlr) +{ + int cfg; + + /* + * Don't know how to deal with a TBI yet. + */ + if(ctlr->mii == nil) { + iprint("83820: got tbi, not phy\n"); + return; + } + + /* + * The polarity of these bits is at the mercy + * of the board designer. + * The correct answer for all speed and duplex questions + * should be to query the phy. + */ + cfg = csr32r(ctlr, Cfg); + if(!(cfg & Dupsts)){ + ctlr->rxcfg |= Rxfd; + ctlr->txcfg |= Csi|Hbi; + iprint("83820: full duplex, "); + } + else{ + ctlr->rxcfg &= ~Rxfd; + ctlr->txcfg &= ~(Csi|Hbi); + iprint("83820: half duplex, "); + } + csr32w(ctlr, Rxcfg, ctlr->rxcfg); + csr32w(ctlr, Txcfg, ctlr->txcfg); + + switch(cfg & (Spdsts1000|Spdsts100)){ + case Spdsts1000: /* 100Mbps */ + default: /* 10Mbps */ + ctlr->cfg &= ~Mode1000; + if ((cfg & (Spdsts1000|Spdsts100)) == Spdsts1000) + iprint("100Mb/s\n"); + else + iprint("10Mb/s\n"); + break; + case Spdsts100: /* 1Gbps */ + ctlr->cfg |= Mode1000; + iprint("1Gb/s\n"); + break; + } + csr32w(ctlr, Cfg, ctlr->cfg); +} + +static void +dp83820init(Ether* edev) +{ + int i; + Ctlr *ctlr; + Desc *desc; + uchar *alloc; + + ctlr = edev->ctlr; + + dp83820halt(ctlr); + + /* + * Receiver + */ + alloc = (uchar*)ROUNDUP((ulong)ctlr->alloc, 8); + ctlr->rd = (Desc*)alloc; + alloc += ctlr->nrd*sizeof(Desc); + memset(ctlr->rd, 0, ctlr->nrd*sizeof(Desc)); + ctlr->rdx = 0; + for(i = 0; i < ctlr->nrd; i++){ + desc = &ctlr->rd[i]; + desc->link = PCIWADDR(&ctlr->rd[NEXT(i, ctlr->nrd)]); + if(dp83820rballoc(desc) == nil) { + print("dp83820init: out of buffers\n"); + continue; + } + } + csr32w(ctlr, Rxdphi, 0); + csr32w(ctlr, Rxdp, PCIWADDR(ctlr->rd)); + + for(i = 0; i < Eaddrlen; i += 2){ + csr32w(ctlr, Rfcr, i); + csr32w(ctlr, Rfdr, (edev->ea[i+1]<<8)|edev->ea[i]); + } + /* for now, accept all multicast packets */ + csr32w(ctlr, Rfcr, Rfen|Aab|Apm|Aam); + + ctlr->rxcfg = Stripcrc|(((2*(ETHERMINTU+4))/8)<imr |= Rxorn|Rxidle|Rxearly|Rxdesc|Rxok; + + /* + * Transmitter. + */ + ctlr->td = (Desc*)alloc; + memset(ctlr->td, 0, ctlr->ntd*sizeof(Desc)); + ctlr->tdh = ctlr->tdt = ctlr->ntq = 0; + for(i = 0; i < ctlr->ntd; i++){ + desc = &ctlr->td[i]; + desc->link = PCIWADDR(&ctlr->td[NEXT(i, ctlr->ntd)]); + } + csr32w(ctlr, Txdphi, 0); + csr32w(ctlr, Txdp, PCIWADDR(ctlr->td)); + + ctlr->txcfg = Atp|(((2*(ETHERMINTU+4))/32)<imr |= Txurn|Txidle|Txdesc|Txok; + + ilock(&ctlr->ilock); + + dp83820cfg(ctlr); + + csr32w(ctlr, Mibc, Aclr); + ctlr->imr |= Mib; + + csr32w(ctlr, Imr, ctlr->imr); + + /* try coalescing adjacent interrupts; use hold-off interval of 100µs */ + csr32w(ctlr, Ihr, Ihctl|(1<ilock); +} + +/* multicast already on, don't need to do anything */ +static void +multicast(void*, uchar*, int) +{ +} + +static void +dp83820attach(Ether* edev) +{ + Block *bp; + Ctlr *ctlr; + + ctlr = edev->ctlr; + qlock(&ctlr->alock); + if(ctlr->alloc != nil){ + qunlock(&ctlr->alock); + return; + } + + if(waserror()){ +err: + if(ctlr->mii != nil){ + free(ctlr->mii); + ctlr->mii = nil; + } + if(ctlr->alloc != nil){ + free(ctlr->alloc); + ctlr->alloc = nil; + } + nexterror(); + } + + if(!(ctlr->cfg & Tbien)){ + if((ctlr->mii = malloc(sizeof(Mii))) == nil) + error(Enomem); + ctlr->mii->ctlr = ctlr; + ctlr->mii->mir = dp83820miimir; + ctlr->mii->miw = dp83820miimiw; + if(mii(ctlr->mii, ~0) == 0) + error("no PHY"); + ctlr->cfg |= Dupstsien|Lnkstsien|Spdstsien; + ctlr->imr |= Phy; + } + + /* allocate all Descs */ + ctlr->nrd = Nrd; + ctlr->nrb = Nrb; + ctlr->ntd = Ntd; + ctlr->alloc = mallocz((ctlr->nrd+ctlr->ntd)*sizeof(Desc) + 7, 0); + if(ctlr->alloc == nil) + error(Enomem); + + /* + * allocate receive Blocks+buffers, add all to receive Block+buffer pool + */ + for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){ + if((bp = iallocb(Rbsz)) == nil) { + print( + "dp83820attach: iallocb failed with %d rcv bufs allocated\n", + ctlr->nrb); + error(Enomem); + } +#ifdef FS + bp->flags |= Mbrcvbuf; +#endif + bp->free = dp83820rbfree; /* to be called via freeb() */ + dp83820rbfree(bp); + } + + /* attaches a receive Block+buffer to each receive Desc */ + dp83820init(edev); + + qunlock(&ctlr->alock); + poperror(); + return; + + goto err; +} + +static void +dp83820transmit(Ether* edev) +{ + Block *bp; + Ctlr *ctlr; + Desc *desc; + int cmdsts, r, x; + + ctlr = edev->ctlr; + + ilock(&ctlr->tlock); + + bp = nil; + for(x = ctlr->tdh; ctlr->ntq; x = NEXT(x, ctlr->ntd)){ + desc = &ctlr->td[x]; + if((cmdsts = desc->cmdsts) & Own) + break; + if(!(cmdsts & Ok)){ + if(cmdsts & Ec) + ctlr->ec++; + if(cmdsts & Owc) + ctlr->owc++; + if(cmdsts & Ed) + ctlr->ed++; + if(cmdsts & Crs) + ctlr->crs++; + if(cmdsts & Tfu) + ctlr->tfu++; + if(cmdsts & Txa) + ctlr->txa++; +#ifndef FS + edev->oerrs++; +#endif + } + desc->bp->next = bp; /* chain transmitted Blocks together */ + bp = desc->bp; + desc->bp = nil; /* unlink them from Descs */ + + ctlr->ntq--; + } + /* free Blocks+buffers comprising the packets just sent */ + ctlr->tdh = x; + if(bp != nil) + freeblist(bp); + + x = ctlr->tdt; + while(ctlr->ntq < (ctlr->ntd-1)){ + bp = etheroq(edev); /* get head of transmit q */ + if(bp == nil) + break; + + desc = &ctlr->td[x]; + desc->bufptr = PCIWADDR(bp->rp); + desc->bp = bp; /* attach to Desc */ + ctlr->ntq++; + coherence(); + desc->cmdsts = Own|Intr|BLEN(bp); /* fire! */ + + x = NEXT(x, ctlr->ntd); + } + if (ctlr->ntq >= ctlr->ntd-1) + iprint("83820: xmit q full, Ntd=%d\n", Ntd); + if(x != ctlr->tdt){ + ctlr->tdt = x; + r = csr32r(ctlr, Cr); + csr32w(ctlr, Cr, Txe|r); + } + + iunlock(&ctlr->tlock); +} + +static void +dp83820interrupt(Ureg*, void* arg) +{ + Block *bp; + Ctlr *ctlr; + Desc *desc; + Ether *edev; + int i, isr, r, x, rcvd = 0; + + edev = arg; + ctlr = edev->ctlr; + + for(isr = csr32r(ctlr, Isr); isr & ctlr->imr; isr = csr32r(ctlr, Isr)){ + if(isr & (Rxorn|Rxidle|Rxearly|Rxdesc|Rxok)){ + x = ctlr->rdx; + desc = &ctlr->rd[x]; + while(desc->cmdsts & Own){ + if((desc->cmdsts & Ok) && desc->bp != nil){ + /* unlink rcv. Block from Desc */ + bp = desc->bp; + desc->bp = nil; + /* store its length, add to input q */ + INCRPTR(bp, desc->cmdsts & SizeMASK); + ETHERIQ(edev, bp, 1); + rcvd++; + } + /* replace rcv. Block just detached from Desc */ + if (dp83820rballoc(desc) == nil) + iprint( + "dp83820interrupt: rballoc failed\n"); + + x = NEXT(x, ctlr->nrd); + desc = &ctlr->rd[x]; + } + ctlr->rdx = x; + if (rcvd >= ctlr->nrd-1) + iprint("83820: rcv q full, Nrd=%d\n", Nrd); + + if(isr & Rxidle){ + /* resume reading packets */ + r = csr32r(ctlr, Cr); + csr32w(ctlr, Cr, Rxe|r); + ctlr->rxidle++; + } + + isr &= ~(Rxorn|Rxidle|Rxearly|Rxdesc|Rxok); + } + + if(isr & (Txurn|Txidle|Txdesc|Txok)){ + /* toss completed packets, q new ones, fire */ + dp83820transmit(edev); + isr &= ~(Txurn|Txidle|Txdesc|Txok); + } + + if(isr & Mib){ + for(i = 0; i < Nmibd; i++){ + r = csr32r(ctlr, Mibd+(i*sizeof(int))); + ctlr->mibd[i] += r & 0xFFFF; + } + isr &= ~Mib; + } + + if((isr & Phy) && ctlr->mii != nil){ + ctlr->mii->mir(ctlr->mii, 1, Bmsr); + print("phy: cfg %8.8ux bmsr %4.4ux\n", + csr32r(ctlr, Cfg), + ctlr->mii->mir(ctlr->mii, 1, Bmsr)); + dp83820cfg(ctlr); + isr &= ~Phy; + } + if(isr) + iprint("dp83820: isr %8.8ux\n", isr); + } +} + +#ifndef FS +static long +dp83820ifstat(Ether* edev, void* a, long n, ulong offset) +{ + char *p; + Ctlr *ctlr; + int i, l, r; + MiiPhy *phy; + + ctlr = edev->ctlr; + + edev->crcs = ctlr->mibd[1]; + edev->frames = ctlr->mibd[3]; + edev->buffs = ctlr->mibd[5]; + edev->overflows = ctlr->mibd[2]; + + if(n == 0) + return 0; + + p = malloc(READSTR); + l = 0; + for(i = 0; i < Nmibd; i++){ + r = csr32r(ctlr, Mibd+(i*sizeof(int))); + ctlr->mibd[i] += r & 0xFFFF; + if(ctlr->mibd[i] != 0 && dp83820mibs[i] != nil) + l += snprint(p+l, READSTR-l, "%s: %ud %ud\n", + dp83820mibs[i], ctlr->mibd[i], r); + } + l += snprint(p+l, READSTR-l, "rxidle %d\n", ctlr->rxidle); + l += snprint(p+l, READSTR-l, "ec %d\n", ctlr->ec); + l += snprint(p+l, READSTR-l, "owc %d\n", ctlr->owc); + l += snprint(p+l, READSTR-l, "ed %d\n", ctlr->ed); + l += snprint(p+l, READSTR-l, "crs %d\n", ctlr->crs); + l += snprint(p+l, READSTR-l, "tfu %d\n", ctlr->tfu); + l += snprint(p+l, READSTR-l, "txa %d\n", ctlr->txa); + + l += snprint(p+l, READSTR, "rom:"); + for(i = 0; i < 0x10; i++){ + if(i && ((i & 0x07) == 0)) + l += snprint(p+l, READSTR-l, "\n "); + l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->eeprom[i]); + } + l += snprint(p+l, READSTR-l, "\n"); + USED(l); + if(0 && ctlr->mii != nil && (phy = ctlr->mii->curphy) != nil){ + l += snprint(p+l, READSTR, "phy:"); + for(i = 0; i < NMiiPhyr; i++){ + if(i && ((i & 0x07) == 0)) + l += snprint(p+l, READSTR-l, "\n "); + /* phy->r no longer exists */ + // l += snprint(p+l, READSTR-l, " %4.4uX", phy->r[i]); + } + snprint(p+l, READSTR-l, "\n"); + } + + n = readstr(offset, a, n, p); + free(p); + + return n; +} +#endif /* FS */ + +static void +dp83820promiscuous(void* arg, int on) +{ + USED(arg, on); +} + +static int +atc93c46r(Ctlr* ctlr, int address) +{ + int data, i, mear, r, size; + + /* + * Analog Technology, Inc. ATC93C46 + * or equivalent serial EEPROM. + */ + mear = csr32r(ctlr, Mear); + mear &= ~(Eesel|Eeclk|Eedo|Eedi); + r = Eesel|mear; + +reread: + csr32w(ctlr, Mear, r); + data = 0x06; + for(i = 3-1; i >= 0; i--){ + if(data & (1<eepromsz) == 0) + size = 8; + + for(size = size-1; size >= 0; size--){ + if(address & (1<= 0; i--){ + csr32w(ctlr, Mear, Eeclk|r); + microdelay(1); + if(csr32r(ctlr, Mear) & Eedo) + data |= (1<eepromsz == 0){ + ctlr->eepromsz = 8-size; + ctlr->eeprom = malloc((1<eepromsz)*sizeof(ushort)); + goto reread; + } + + return data; +} + +static void +resetctlr(Ctlr *ctlr) +{ + csr32w(ctlr, Cr, Rst); + delay(1); + /* TODO: limit this; don't wait forever */ + while(csr32r(ctlr, Cr) & Rst) + delay(1); + + atc93c46r(ctlr, 0); +} + +static void +shutdown(Ether* ether) +{ + Ctlr *ctlr = ether->ctlr; + +print("ether83820 shutting down\n"); + csr32w(ctlr, Cr, Txd|Rxd); /* disable transceiver */ + resetctlr(ctlr); +} + +int +dp83820reset(Ctlr* ctlr) +{ + int i, r; + unsigned char sum; + + /* + * Soft reset the controller; + * read the EEPROM to get the initial settings + * of the Cfg and Gpior bits which should be cleared by + * the reset. + */ + resetctlr(ctlr); + sum = 0; + for(i = 0; i < 0x0E; i++){ + r = atc93c46r(ctlr, i); + ctlr->eeprom[i] = r; + sum += r; + sum += r>>8; + } + + if(sum != 0){ + print("dp83820reset: bad EEPROM checksum\n"); + return -1; + } + +#ifdef notdef + csr32w(ctlr, Gpior, ctlr->eeprom[4]); + + cfg = Extstsen|Exd; + r = csr32r(ctlr, Cfg); + if(ctlr->eeprom[5] & 0x0001) + cfg |= Ext125; + if(ctlr->eeprom[5] & 0x0002) + cfg |= M64addren; + if((ctlr->eeprom[5] & 0x0004) && (r & Pci64det)) + cfg |= Data64en; + if(ctlr->eeprom[5] & 0x0008) + cfg |= T64addren; + if(!(pcicfgr16(ctlr->pcidev, PciPCR) & 0x10)) + cfg |= Mwidis; + if(ctlr->eeprom[5] & 0x0020) + cfg |= Mrmdis; + if(ctlr->eeprom[5] & 0x0080) + cfg |= Mode1000; + if(ctlr->eeprom[5] & 0x0200) + cfg |= Tbien|Mode1000; + /* + * What about RO bits we might have destroyed with Rst? + * What about Exd, Tmrtest, Extstsen, Pintctl? + * Why does it think it has detected a 64-bit bus when + * it hasn't? + */ +#else + //r = csr32r(ctlr, Cfg); + //r &= ~(Mode1000|T64addren|Data64en|M64addren); + //csr32w(ctlr, Cfg, r); + //csr32w(ctlr, Cfg, 0x2000); +#endif /* notdef */ + ctlr->cfg = csr32r(ctlr, Cfg); +print("cfg %8.8ux pcicfg %8.8ux\n", ctlr->cfg, pcicfgr32(ctlr->pcidev, PciPCR)); + ctlr->cfg &= ~(T64addren|Data64en|M64addren); + csr32w(ctlr, Cfg, ctlr->cfg); + csr32w(ctlr, Mibc, Aclr|Frz); + + return 0; +} + +// from pci.c +enum { + Pcinetctlr = 0x02, /* network controller */ +// PciCCRp = 0x09, /* programming interface class code */ +// PciCCRu = 0x0A, /* sub-class code */ +// PciCCRb = 0x0B, /* base class code */ +}; + +static void +dp83820pci(void) +{ + int port; + Pcidev *p; + Ctlr *ctlr; + + p = nil; + while(p = pcimatch(p, 0, 0)){ + /* ccru is a short in the FS kernel, thus the cast to uchar */ + if(p->ccrb != Pcinetctlr || (uchar)p->ccru != 0) + continue; + switch((p->did<<16)|p->vid){ + default: + continue; + case (0x0022<<16)|0x100B: /* DP83820 (Gig-NIC) */ + break; + } + + port = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0); + if(port == 0){ + print("DP83820: can't map %8.8lux\n", p->mem[1].bar); + continue; + } + /* malloc only zeroes storage if Npadlong!=0, so use mallocz */ + ctlr = mallocz(sizeof(Ctlr), 1); + ctlr->port = port; + ctlr->pcidev = p; + ctlr->id = (p->did<<16)|p->vid; + +#ifdef notdef + /* + * bar[0] is the I/O port register address and + * bar[1] is the memory-mapped register address. + */ + if (ioalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0, "dp83820") + < 0) { + print("dp83820: port 0x%uX in use\n", ctlr->port); + free(ctlr); + continue; + } +#endif + ctlr->nic = KADDR(ctlr->port); + if(dp83820reset(ctlr)){ + free(ctlr); + continue; + } + pcisetbme(p); + + if(dp83820ctlrhead != nil) + dp83820ctlrtail->next = ctlr; + else + dp83820ctlrhead = ctlr; + dp83820ctlrtail = ctlr; + } +} + +int +dp83820pnp(Ether* edev) +{ + int i; + Ctlr *ctlr; + uchar ea[Eaddrlen]; + + if(dp83820ctlrhead == nil) + dp83820pci(); + + /* + * Any adapter matches if no edev->port is supplied, + * otherwise the ports must match. + */ + for(ctlr = dp83820ctlrhead; 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; + + /* + * Check if the adapter's station address is to be overridden. + * If not, read it from the EEPROM and set in ether->ea prior to + * loading the station address in the hardware. + */ + memset(ea, 0, Eaddrlen); + if(memcmp(ea, edev->ea, Eaddrlen) == 0){ + for(i = 0; i < Eaddrlen/2; i++){ + edev->ea[2*i] = ctlr->eeprom[0x0C-i]; + edev->ea[2*i+1] = ctlr->eeprom[0x0C-i]>>8; + } + } + + edev->attach = dp83820attach; + edev->transmit = dp83820transmit; + edev->interrupt = dp83820interrupt; +#ifndef FS + edev->ifstat = dp83820ifstat; + edev->arg = edev; + edev->shutdown = shutdown; + edev->multicast = multicast; + edev->promiscuous = dp83820promiscuous; +#endif + return 0; +} + +#ifndef FS +void +etherdp83820link(void) +{ + addethercard("DP83820", dp83820pnp); +} +#endif --- /sys/src/9/pc/etherelnk3.c Sat Apr 17 18:59:33 2004 +++ /sys/src/9/pc/etherelnk3.c Sat Apr 17 18:59:32 2004 @@ -1748,6 +1748,35 @@ return EEPROMDATA(port); } +static void +resetctlr(Ctlr *ctlr) +{ + int x, port = ctlr->port; + + txrxreset(port); + x = ins(port+ResetOp905B); + XCVRDEBUG("905[BC] reset ops 0x%uX\n", x); + x &= ~0x4010; + if(ctlr->did == 0x5157){ + x |= 0x0010; /* Invert LED */ + outs(port+ResetOp905B, x); + } + if(ctlr->did == 0x6056){ + x |= 0x4000; + outs(port+ResetOp905B, x); + + COMMAND(port, SelectRegisterWindow, Wsetup); + outs(port, 0x0800); + } +} + +static void +shutdown(Ether *ether) +{ +print("etherelnk3 shutting down\n"); + resetctlr(ether->ctlr); +} + int etherelnk3reset(Ether* ether) { @@ -1899,21 +1928,7 @@ case 0x9200: case 0x9201: ctlr->xcvr = xcvrMii; - txrxreset(port); - x = ins(port+ResetOp905B); - XCVRDEBUG("905[BC] reset ops 0x%uX\n", x); - x &= ~0x4010; - if(ctlr->did == 0x5157){ - x |= 0x0010; /* Invert LED */ - outs(port+ResetOp905B, x); - } - if(ctlr->did == 0x6056){ - x |= 0x4000; - outs(port+ResetOp905B, x); - - COMMAND(port, SelectRegisterWindow, Wsetup); - outs(port, 0x0800); - } + resetctlr(ctlr); break; } XCVRDEBUG("xcvr selected: %uX, did 0x%uX\n", ctlr->xcvr, ctlr->did); @@ -2102,6 +2117,7 @@ ether->promiscuous = promiscuous; ether->multicast = multicast; + ether->shutdown = shutdown; ether->arg = ether; return 0; --- /sys/src/9/pc/etherigbe.c Sat Apr 17 18:59:34 2004 +++ /sys/src/9/pc/etherigbe.c Sat Apr 17 18:59:34 2004 @@ -1631,6 +1631,13 @@ ; } +static void +igbeshutdown(Ether* ether) +{ +print("etherigbe shutting down\n"); + igbedetach(ether->ctlr); +} + static int igbereset(Ctlr* ctlr) { @@ -1846,6 +1853,7 @@ edev->arg = edev; edev->promiscuous = igbepromiscuous; + edev->shutdown = igbeshutdown; edev->multicast = igbemulticast; return 0; --- /sys/src/9/pc/etherrhine.c Sat Apr 17 18:59:35 2004 +++ /sys/src/9/pc/etherrhine.c Sat Apr 17 18:59:34 2004 @@ -480,7 +480,8 @@ edev = arg; ctlr = edev->ctlr; ilock(&ctlr->lock); - iow8(ctlr, Rcr, ior8(ctlr, Rcr) | (enable ? RxProm : RxBcast)); + iow8(ctlr, Rcr, (ior8(ctlr, Rcr) & ~(RxProm|RxBcast)) | + (enable ? RxProm : RxBcast)); iunlock(&ctlr->lock); } @@ -543,17 +544,19 @@ return 0; } +/* multicast already on, don't need to do anything */ static void -init(Ether *edev) +multicast(void*, uchar*, int) { - Ctlr *ctlr; - MiiPhy *phy; - int i; +} - ctlr = edev->ctlr; +static void +shutdown(Ether *edev) +{ + int i; + Ctlr *ctlr = edev->ctlr; ilock(&ctlr->lock); - pcisetbme(ctlr->pci); iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop); @@ -566,7 +569,20 @@ } if (i == Nwait) iprint("etherrhine: reset timeout\n"); + iunlock(&ctlr->lock); +} +static void +init(Ether *edev) +{ + Ctlr *ctlr; + MiiPhy *phy; + int i; + + shutdown(edev); + + ctlr = edev->ctlr; + ilock(&ctlr->lock); iow8(ctlr, Eecsr, ior8(ctlr, Eecsr) | EeAutoLoad); for (i = 0; i < Nwait; ++i) { if ((ior8(ctlr, Eecsr) & EeAutoLoad) == 0) @@ -598,6 +614,7 @@ iow16(ctlr, Imr, 0); iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop); + iow8(ctlr, Rcr, ior8(ctlr, Rcr) | RxMcast); iunlock(&ctlr->lock); } @@ -705,7 +722,8 @@ edev->transmit = transmit; edev->ifstat = ifstat; edev->promiscuous = promiscuous; - + edev->multicast = multicast; + edev->shutdown = shutdown; return 0; }