172cfc098SDavid du Colombier /*
272cfc098SDavid du Colombier * VIA VT6105M Fast Ethernet Controller (Rhine III).
372cfc098SDavid du Colombier * To do:
472cfc098SDavid du Colombier * reorganise initialisation/shutdown/reset
572cfc098SDavid du Colombier * adjust Tx FIFO threshold on underflow - untested
672cfc098SDavid du Colombier * why does the link status never cause an interrupt?
772cfc098SDavid du Colombier * use the lproc as a periodic timer for stalls, etc.
872cfc098SDavid du Colombier * take non-HW stuff out of descriptor for 64-bit
972cfc098SDavid du Colombier * cleanliness
1072cfc098SDavid du Colombier * why does the receive buffer alloc have a +3?
1172cfc098SDavid du Colombier */
1272cfc098SDavid du Colombier #include "u.h"
1372cfc098SDavid du Colombier #include "../port/lib.h"
1472cfc098SDavid du Colombier #include "mem.h"
1572cfc098SDavid du Colombier #include "dat.h"
1672cfc098SDavid du Colombier #include "fns.h"
1772cfc098SDavid du Colombier #include "io.h"
1872cfc098SDavid du Colombier #include "../port/error.h"
1972cfc098SDavid du Colombier #include "../port/netif.h"
2072cfc098SDavid du Colombier
2172cfc098SDavid du Colombier #include "etherif.h"
2272cfc098SDavid du Colombier #include "ethermii.h"
2372cfc098SDavid du Colombier
2472cfc098SDavid du Colombier enum {
2572cfc098SDavid du Colombier Par0 = 0x00, /* Ethernet Address */
2672cfc098SDavid du Colombier Rcr = 0x06, /* Receive Configuration */
2772cfc098SDavid du Colombier Tcr = 0x07, /* Transmit Configuration */
2872cfc098SDavid du Colombier Cr = 0x08, /* Control */
2972cfc098SDavid du Colombier Tqw = 0x0A, /* Transmit Queue Wake */
3072cfc098SDavid du Colombier Isr = 0x0C, /* Interrupt Status */
3172cfc098SDavid du Colombier Imr = 0x0E, /* Interrupt Mask */
3272cfc098SDavid du Colombier Mcfilt0 = 0x10, /* Multicast Filter 0 */
3372cfc098SDavid du Colombier Mcfilt1 = 0x14, /* Multicast Filter 1 */
3472cfc098SDavid du Colombier Rxdaddr = 0x18, /* Current Rd Address */
3572cfc098SDavid du Colombier Txdaddr = 0x1C, /* Current Td Address */
3672cfc098SDavid du Colombier Phyadr = 0x6C, /* Phy Address */
3772cfc098SDavid du Colombier Miisr = 0x6D, /* MII Status */
3872cfc098SDavid du Colombier Bcr0 = 0x6E, /* Bus Control */
3972cfc098SDavid du Colombier Bcr1 = 0x6F,
4072cfc098SDavid du Colombier Miicr = 0x70, /* MII Control */
4172cfc098SDavid du Colombier Miiadr = 0x71, /* MII Address */
4272cfc098SDavid du Colombier Miidata = 0x72, /* MII Data */
4372cfc098SDavid du Colombier Eecsr = 0x74, /* EEPROM Control and Status */
4472cfc098SDavid du Colombier CfgA = 0x78, /* Chip Configuration A */
4572cfc098SDavid du Colombier CfgB = 0x79,
4672cfc098SDavid du Colombier CfgC = 0x7A,
4772cfc098SDavid du Colombier CfgD = 0x7B,
4872cfc098SDavid du Colombier Cr0 = 0x80, /* Miscellaneous Control */
4972cfc098SDavid du Colombier Cr1 = 0x81,
5072cfc098SDavid du Colombier Pmcc = 0x82, /* Power Mgmt Capability Control */
5172cfc098SDavid du Colombier Stickhw = 0x83, /* Sticky Hardware Control */
5272cfc098SDavid du Colombier Misr = 0x84, /* MII Interrupt Control */
5372cfc098SDavid du Colombier Mimr = 0x85, /* MII Interrupt Mask */
5472cfc098SDavid du Colombier Wolcrclr = 0xA4,
5572cfc098SDavid du Colombier Wolcgclr = 0xA7,
5672cfc098SDavid du Colombier Pwrcsrclr = 0xAC,
5772cfc098SDavid du Colombier };
5872cfc098SDavid du Colombier
5972cfc098SDavid du Colombier enum { /* Rcr */
6072cfc098SDavid du Colombier Sep = 0x01, /* Accept Error Packets */
6172cfc098SDavid du Colombier Ar = 0x02, /* Accept Small Packets */
6272cfc098SDavid du Colombier Am = 0x04, /* Accept Multicast */
6372cfc098SDavid du Colombier Ab = 0x08, /* Accept Broadcast */
6472cfc098SDavid du Colombier Prom = 0x10, /* Accept Physical Address Packets */
6572cfc098SDavid du Colombier RrftMASK = 0xE0, /* Receive FIFO Threshold */
6672cfc098SDavid du Colombier RrftSHIFT = 5,
6772cfc098SDavid du Colombier Rrft64 = 0<<RrftSHIFT,
6872cfc098SDavid du Colombier Rrft32 = 1<<RrftSHIFT,
6972cfc098SDavid du Colombier Rrft128 = 2<<RrftSHIFT,
7072cfc098SDavid du Colombier Rrft256 = 3<<RrftSHIFT,
7172cfc098SDavid du Colombier Rrft512 = 4<<RrftSHIFT,
7272cfc098SDavid du Colombier Rrft768 = 5<<RrftSHIFT,
7372cfc098SDavid du Colombier Rrft1024 = 6<<RrftSHIFT,
7472cfc098SDavid du Colombier RrftSAF = 7<<RrftSHIFT,
7572cfc098SDavid du Colombier };
7672cfc098SDavid du Colombier
7772cfc098SDavid du Colombier enum { /* Tcr */
7872cfc098SDavid du Colombier Lb0 = 0x02, /* Loopback Mode */
7972cfc098SDavid du Colombier Lb1 = 0x04,
8072cfc098SDavid du Colombier Ofset = 0x08, /* Select Back-off Priority */
8172cfc098SDavid du Colombier RtsfMASK = 0xE0, /* Transmit FIFO Threshold */
8272cfc098SDavid du Colombier RtsfSHIFT = 5,
8372cfc098SDavid du Colombier Rtsf128 = 0<<RtsfSHIFT,
8472cfc098SDavid du Colombier Rtsf256 = 1<<RtsfSHIFT,
8572cfc098SDavid du Colombier Rtsf512 = 2<<RtsfSHIFT,
8672cfc098SDavid du Colombier Rtsf1024 = 3<<RtsfSHIFT,
8772cfc098SDavid du Colombier RtsfSAF = 7<<RtsfSHIFT,
8872cfc098SDavid du Colombier };
8972cfc098SDavid du Colombier
9072cfc098SDavid du Colombier enum { /* Cr */
9172cfc098SDavid du Colombier Init = 0x0001, /* INIT Process Begin */
9272cfc098SDavid du Colombier Strt = 0x0002, /* Start NIC */
9372cfc098SDavid du Colombier Stop = 0x0004, /* Stop NIC */
9472cfc098SDavid du Colombier Rxon = 0x0008, /* Turn on Receive Process */
9572cfc098SDavid du Colombier Txon = 0x0010, /* Turn on Transmit Process */
9672cfc098SDavid du Colombier Tdmd = 0x0020, /* Transmit Poll Demand */
9772cfc098SDavid du Colombier Rdmd = 0x0040, /* Receive Poll Demand */
9872cfc098SDavid du Colombier Eren = 0x0100, /* Early Receive Enable */
9972cfc098SDavid du Colombier Fdx = 0x0400, /* Set MAC to Full Duplex */
10072cfc098SDavid du Colombier Dpoll = 0x0800, /* Disable Td/Rd Auto Polling */
10172cfc098SDavid du Colombier Tdmd1 = 0x2000, /* Transmit Poll Demand 1 */
10272cfc098SDavid du Colombier Rdmd1 = 0x4000, /* Receive Poll Demand 1 */
10372cfc098SDavid du Colombier Sfrst = 0x8000, /* Software Reset */
10472cfc098SDavid du Colombier };
10572cfc098SDavid du Colombier
10672cfc098SDavid du Colombier enum { /* Isr/Imr */
10772cfc098SDavid du Colombier Prx = 0x0001, /* Packet Received OK */
10872cfc098SDavid du Colombier Ptx = 0x0002, /* Packet Transmitted OK */
10972cfc098SDavid du Colombier Rxe = 0x0004, /* Receive Error */
11072cfc098SDavid du Colombier Txe = 0x0008, /* Transmit Error */
11172cfc098SDavid du Colombier Tu = 0x0010, /* Transmit Buffer Underflow */
11272cfc098SDavid du Colombier Ru = 0x0020, /* Receive Buffer Link Error */
11372cfc098SDavid du Colombier Be = 0x0040, /* PCI Bus Error */
11472cfc098SDavid du Colombier Cnt = 0x0080, /* Counter Overflow */
11572cfc098SDavid du Colombier Eri = 0x0100, /* Early Receive Interrupt */
11672cfc098SDavid du Colombier Udfi = 0x0200, /* Tx FIFO Underflow */
11772cfc098SDavid du Colombier Ovfi = 0x0400, /* Receive FIFO Overflow */
11872cfc098SDavid du Colombier Pktrace = 0x0800, /* Hmmm... */
11972cfc098SDavid du Colombier Norbf = 0x1000, /* No Receive Buffers */
12072cfc098SDavid du Colombier Abti = 0x2000, /* Transmission Abort */
12172cfc098SDavid du Colombier Srci = 0x4000, /* Port State Change */
12272cfc098SDavid du Colombier Geni = 0x8000, /* General Purpose Interrupt */
12372cfc098SDavid du Colombier };
12472cfc098SDavid du Colombier
12572cfc098SDavid du Colombier enum { /* Phyadr */
12672cfc098SDavid du Colombier PhyadMASK = 0x1F, /* PHY Address */
12772cfc098SDavid du Colombier PhyadSHIFT = 0,
12872cfc098SDavid du Colombier Mfdc = 0x20, /* Accelerate MDC Speed */
12972cfc098SDavid du Colombier Mpo0 = 0x40, /* MII Polling Timer Interval */
13072cfc098SDavid du Colombier Mpo1 = 0x80,
13172cfc098SDavid du Colombier };
13272cfc098SDavid du Colombier
13372cfc098SDavid du Colombier enum { /* Bcr0 */
13472cfc098SDavid du Colombier DmaMASK = 0x07, /* DMA Length */
13572cfc098SDavid du Colombier DmaSHIFT = 0,
13672cfc098SDavid du Colombier Dma32 = 0<<DmaSHIFT,
13772cfc098SDavid du Colombier Dma64 = 1<<DmaSHIFT,
13872cfc098SDavid du Colombier Dma128 = 2<<DmaSHIFT,
13972cfc098SDavid du Colombier Dma256 = 3<<DmaSHIFT,
14072cfc098SDavid du Colombier Dma512 = 4<<DmaSHIFT,
14172cfc098SDavid du Colombier Dma1024 = 5<<DmaSHIFT,
14272cfc098SDavid du Colombier DmaSAF = 7<<DmaSHIFT,
14372cfc098SDavid du Colombier CrftMASK = 0x38, /* Rx FIFO Threshold */
14472cfc098SDavid du Colombier CrftSHIFT = 3,
14572cfc098SDavid du Colombier Crft64 = 1<<CrftSHIFT,
14672cfc098SDavid du Colombier Crft128 = 2<<CrftSHIFT,
14772cfc098SDavid du Colombier Crft256 = 3<<CrftSHIFT,
14872cfc098SDavid du Colombier Crft512 = 4<<CrftSHIFT,
14972cfc098SDavid du Colombier Crft1024 = 5<<CrftSHIFT,
15072cfc098SDavid du Colombier CrftSAF = 7<<CrftSHIFT,
15172cfc098SDavid du Colombier Extled = 0x40, /* Extra LED Support Control */
15272cfc098SDavid du Colombier Med2 = 0x80, /* Medium Select Control */
15372cfc098SDavid du Colombier };
15472cfc098SDavid du Colombier
15572cfc098SDavid du Colombier enum { /* Bcr1 */
15672cfc098SDavid du Colombier PotMASK = 0x07, /* Polling Timer Interval */
15772cfc098SDavid du Colombier PotSHIFT = 0,
15872cfc098SDavid du Colombier CtftMASK = 0x38, /* Tx FIFO Threshold */
15972cfc098SDavid du Colombier CtftSHIFT = 3,
16072cfc098SDavid du Colombier Ctft64 = 1<<CtftSHIFT,
16172cfc098SDavid du Colombier Ctft128 = 2<<CtftSHIFT,
16272cfc098SDavid du Colombier Ctft256 = 3<<CtftSHIFT,
16372cfc098SDavid du Colombier Ctft512 = 4<<CtftSHIFT,
16472cfc098SDavid du Colombier Ctft1024 = 5<<CtftSHIFT,
16572cfc098SDavid du Colombier CtftSAF = 7<<CtftSHIFT,
16672cfc098SDavid du Colombier };
16772cfc098SDavid du Colombier
16872cfc098SDavid du Colombier enum { /* Miicr */
16972cfc098SDavid du Colombier Mdc = 0x01, /* Clock */
17072cfc098SDavid du Colombier Mdi = 0x02, /* Data In */
17172cfc098SDavid du Colombier Mdo = 0x04, /* Data Out */
17272cfc098SDavid du Colombier Mout = 0x08, /* Output Enable */
17372cfc098SDavid du Colombier Mdpm = 0x10, /* Direct Program Mode Enable */
17472cfc098SDavid du Colombier Wcmd = 0x20, /* Write Enable */
17572cfc098SDavid du Colombier Rcmd = 0x40, /* Read Enable */
17672cfc098SDavid du Colombier Mauto = 0x80, /* Auto Polling Enable */
17772cfc098SDavid du Colombier };
17872cfc098SDavid du Colombier
17972cfc098SDavid du Colombier enum { /* Miiadr */
18072cfc098SDavid du Colombier MadMASK = 0x1F, /* MII Port Address */
18172cfc098SDavid du Colombier MadSHIFT = 0,
18272cfc098SDavid du Colombier Mdone = 0x20, /* Accelerate MDC Speed */
18372cfc098SDavid du Colombier Msrcen = 0x40, /* MII Polling Timer Interval */
18472cfc098SDavid du Colombier Midle = 0x80,
18572cfc098SDavid du Colombier };
18672cfc098SDavid du Colombier
18772cfc098SDavid du Colombier enum { /* Eecsr */
18872cfc098SDavid du Colombier Edo = 0x01, /* Data Out */
18972cfc098SDavid du Colombier Edi = 0x02, /* Data In */
19072cfc098SDavid du Colombier Eck = 0x04, /* Clock */
19172cfc098SDavid du Colombier Ecs = 0x08, /* Chip Select */
19272cfc098SDavid du Colombier Dpm = 0x10, /* Direct Program Mode Enable */
19372cfc098SDavid du Colombier Autold = 0x20, /* Dynamic Reload */
19472cfc098SDavid du Colombier Embp = 0x40, /* Embedded Program Enable */
19572cfc098SDavid du Colombier Eepr = 0x80, /* Programmed */
19672cfc098SDavid du Colombier };
19772cfc098SDavid du Colombier
19872cfc098SDavid du Colombier /*
19972cfc098SDavid du Colombier * Ring descriptor. The space allocated for each
20072cfc098SDavid du Colombier * of these will be rounded up to a cache-line boundary.
20172cfc098SDavid du Colombier * The first 4 elements are known to the hardware.
20272cfc098SDavid du Colombier */
20372cfc098SDavid du Colombier typedef struct Ds Ds;
20472cfc098SDavid du Colombier typedef struct Ds {
20572cfc098SDavid du Colombier u32int status;
20672cfc098SDavid du Colombier u32int control;
20772cfc098SDavid du Colombier u32int addr;
20872cfc098SDavid du Colombier u32int branch;
20972cfc098SDavid du Colombier
21072cfc098SDavid du Colombier Block* bp;
21172cfc098SDavid du Colombier Ds* next;
21272cfc098SDavid du Colombier Ds* prev;
21372cfc098SDavid du Colombier } Ds;
21472cfc098SDavid du Colombier
21572cfc098SDavid du Colombier enum { /* Rx Ds status */
21672cfc098SDavid du Colombier Rerr = 0x00000001, /* Buff|Rxserr|Fov|Fae|Crc */
21772cfc098SDavid du Colombier Crc = 0x00000002, /* CRC Error */
21872cfc098SDavid du Colombier Fae = 0x00000004, /* Frame Alignment Error */
21972cfc098SDavid du Colombier Fov = 0x00000008, /* FIFO Overflow */
22072cfc098SDavid du Colombier Long = 0x00000010, /* A Long Packet */
22172cfc098SDavid du Colombier Runt = 0x00000020, /* A Runt Packet */
22272cfc098SDavid du Colombier Rxserr = 0x00000040, /* System Error */
22372cfc098SDavid du Colombier Buff = 0x00000080, /* Buffer Underflow Error */
22472cfc098SDavid du Colombier Rxedp = 0x00000100, /* End of Packet Buffer */
22572cfc098SDavid du Colombier Rxstp = 0x00000200, /* Packet Start */
22672cfc098SDavid du Colombier Chn = 0x00000400, /* Chain Buffer */
22772cfc098SDavid du Colombier Phy = 0x00000800, /* Physical Address Packet */
22872cfc098SDavid du Colombier Bar = 0x00001000, /* Broadcast Packet */
22972cfc098SDavid du Colombier Mar = 0x00002000, /* Multicast Packet */
23072cfc098SDavid du Colombier Rxok = 0x00008000, /* Packet Received OK */
23172cfc098SDavid du Colombier LengthMASK = 0x07FF0000, /* Received Packet Length */
23272cfc098SDavid du Colombier LengthSHIFT = 16,
23372cfc098SDavid du Colombier
23472cfc098SDavid du Colombier Own = 0x80000000, /* Descriptor Owned by NIC */
23572cfc098SDavid du Colombier };
23672cfc098SDavid du Colombier
23772cfc098SDavid du Colombier enum { /* Rx Ds control */
23872cfc098SDavid du Colombier RbsizeMASK = 0x000007FF, /* Receive Buffer Size */
23972cfc098SDavid du Colombier RbsizeSHIFT = 0,
24072cfc098SDavid du Colombier Tag = 0x00010000, /* Receive a Tagged Packet */
24172cfc098SDavid du Colombier Udpkt = 0x00020000, /* Receive a UDP Packet */
24272cfc098SDavid du Colombier Tcpkt = 0x00040000, /* Receive a TCP Packet */
24372cfc098SDavid du Colombier Ipkt = 0x00080000, /* Receive an IP Packet */
24472cfc098SDavid du Colombier Tuok = 0x00100000, /* TCP/UDP Checksum OK */
24572cfc098SDavid du Colombier Ipok = 0x00200000, /* IP Checksum OK */
24672cfc098SDavid du Colombier Snaptag = 0x00400000, /* Snap Packet + 802.1q Tag */
24772cfc098SDavid du Colombier Rxlerr = 0x00800000, /* Receive Length Check Error */
24872cfc098SDavid du Colombier IpktMASK = 0xff000000, /* Interesting Packet */
24972cfc098SDavid du Colombier IpktSHIFT = 24,
25072cfc098SDavid du Colombier };
25172cfc098SDavid du Colombier
25272cfc098SDavid du Colombier enum { /* Tx Ds status */
25372cfc098SDavid du Colombier NcrMASK = 0x0000000F, /* Collision Retry Count */
25472cfc098SDavid du Colombier NcrSHIFT = 0,
25572cfc098SDavid du Colombier Cols = 0x00000010, /* Experienced Collisions */
25672cfc098SDavid du Colombier Cdh = 0x00000080, /* CD Heartbeat */
25772cfc098SDavid du Colombier Abt = 0x00000100, /* Aborted after Excessive Collisions */
25872cfc098SDavid du Colombier Owc = 0x00000200, /* Out of Window Collision */
25972cfc098SDavid du Colombier Crs = 0x00000400, /* Carrier Sense Lost */
26072cfc098SDavid du Colombier Udf = 0x00000800, /* FIFO Underflow */
26172cfc098SDavid du Colombier Tbuff = 0x00001000, /* Invalid Td */
26272cfc098SDavid du Colombier Txserr = 0x00002000, /* System Error */
26372cfc098SDavid du Colombier Terr = 0x00008000, /* Excessive Collisions */
26472cfc098SDavid du Colombier };
26572cfc098SDavid du Colombier
26672cfc098SDavid du Colombier enum { /* Tx Ds control */
26772cfc098SDavid du Colombier TbsMASK = 0x000007FF, /* Tx Buffer Size */
26872cfc098SDavid du Colombier TbsSHIFT = 0,
26972cfc098SDavid du Colombier Chain = 0x00008000, /* Chain Buffer */
27072cfc098SDavid du Colombier Crcdisable = 0x00010000, /* Disable CRC generation */
27172cfc098SDavid du Colombier Stp = 0x00200000, /* Start of Packet */
27272cfc098SDavid du Colombier Edp = 0x00400000, /* End of Packet */
27372cfc098SDavid du Colombier Ic = 0x00800000, /* Interrupt Control */
27472cfc098SDavid du Colombier };
27572cfc098SDavid du Colombier
27672cfc098SDavid du Colombier enum { /* Tx Ds branch */
27772cfc098SDavid du Colombier Tdctl = 0x00000001, /* No Interrupt Generated */
27872cfc098SDavid du Colombier };
27972cfc098SDavid du Colombier
28072cfc098SDavid du Colombier enum {
28172cfc098SDavid du Colombier Nrd = 196,
2826520663fSDavid du Colombier Ntd = 64,
28372cfc098SDavid du Colombier Crcsz = 4,
28472cfc098SDavid du Colombier Bslop = 48,
28572cfc098SDavid du Colombier Rdbsz = ETHERMAXTU+Crcsz+Bslop,
286*5b797632SDavid du Colombier Maxus = 1000000, /* Soekris 5501s take a while to reset */
28772cfc098SDavid du Colombier
28872cfc098SDavid du Colombier Nrxstats = 8,
28972cfc098SDavid du Colombier Ntxstats = 9,
29072cfc098SDavid du Colombier };
29172cfc098SDavid du Colombier
29272cfc098SDavid du Colombier typedef struct Ctlr Ctlr;
29372cfc098SDavid du Colombier typedef struct Ctlr {
29472cfc098SDavid du Colombier int port;
29572cfc098SDavid du Colombier Pcidev* pcidev;
29672cfc098SDavid du Colombier Ctlr* next;
29772cfc098SDavid du Colombier int active;
29872cfc098SDavid du Colombier int id;
29972cfc098SDavid du Colombier uchar par[Eaddrlen];
30072cfc098SDavid du Colombier
30172cfc098SDavid du Colombier QLock alock; /* attach */
30272cfc098SDavid du Colombier void* alloc; /* descriptors, etc. */
30372cfc098SDavid du Colombier int cls; /* alignment */
30472cfc098SDavid du Colombier int nrd;
30572cfc098SDavid du Colombier int ntd;
30672cfc098SDavid du Colombier
30772cfc098SDavid du Colombier Ds* rd;
30872cfc098SDavid du Colombier Ds* rdh;
30972cfc098SDavid du Colombier
31072cfc098SDavid du Colombier Lock tlock;
31172cfc098SDavid du Colombier Ds* td;
31272cfc098SDavid du Colombier Ds* tdh;
31372cfc098SDavid du Colombier Ds* tdt;
31472cfc098SDavid du Colombier int tdused;
31572cfc098SDavid du Colombier
31672cfc098SDavid du Colombier Lock clock; /* */
31772cfc098SDavid du Colombier int cr;
31872cfc098SDavid du Colombier int imr;
31972cfc098SDavid du Colombier int tft; /* Tx threshold */
32072cfc098SDavid du Colombier
32172cfc098SDavid du Colombier Mii* mii;
32272cfc098SDavid du Colombier Rendez lrendez;
32372cfc098SDavid du Colombier int lwakeup;
32472cfc098SDavid du Colombier
32572cfc098SDavid du Colombier uint rxstats[Nrxstats]; /* statistics */
32672cfc098SDavid du Colombier uint txstats[Ntxstats];
32772cfc098SDavid du Colombier ulong totalt;
32872cfc098SDavid du Colombier uint intr;
32972cfc098SDavid du Colombier uint lintr;
33072cfc098SDavid du Colombier uint lsleep;
33172cfc098SDavid du Colombier uint rintr;
33272cfc098SDavid du Colombier uint tintr;
33372cfc098SDavid du Colombier uint txdw;
33472cfc098SDavid du Colombier int tdumax;
33572cfc098SDavid du Colombier
33672cfc098SDavid du Colombier uint abt;
33772cfc098SDavid du Colombier uint tbuff;
33872cfc098SDavid du Colombier uint udf;
33972cfc098SDavid du Colombier
34072cfc098SDavid du Colombier uint abti;
34172cfc098SDavid du Colombier uint udfi;
34272cfc098SDavid du Colombier uint tu;
34372cfc098SDavid du Colombier
34472cfc098SDavid du Colombier uint tuok;
34572cfc098SDavid du Colombier uint ipok;
34672cfc098SDavid du Colombier } Ctlr;
34772cfc098SDavid du Colombier
34872cfc098SDavid du Colombier static Ctlr* vt6105Mctlrhead;
34972cfc098SDavid du Colombier static Ctlr* vt6105Mctlrtail;
35072cfc098SDavid du Colombier
35172cfc098SDavid du Colombier #define csr8r(c, r) (inb((c)->port+(r)))
35272cfc098SDavid du Colombier #define csr16r(c, r) (ins((c)->port+(r)))
35372cfc098SDavid du Colombier #define csr32r(c, r) (inl((c)->port+(r)))
35472cfc098SDavid du Colombier #define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
35572cfc098SDavid du Colombier #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
35672cfc098SDavid du Colombier #define csr32w(c, r, w) (outl((c)->port+(r), (ulong)(w)))
35772cfc098SDavid du Colombier
35872cfc098SDavid du Colombier static Lock vt6105Mrblock; /* receive Block freelist */
35972cfc098SDavid du Colombier static Block* vt6105Mrbpool;
36072cfc098SDavid du Colombier static uint vt6105Mrbpoolsz;
36172cfc098SDavid du Colombier
36272cfc098SDavid du Colombier typedef struct Regs Regs;
36372cfc098SDavid du Colombier typedef struct Regs {
36472cfc098SDavid du Colombier char* name;
36572cfc098SDavid du Colombier int offset;
36672cfc098SDavid du Colombier int size;
36772cfc098SDavid du Colombier } Regs;
36872cfc098SDavid du Colombier
36972cfc098SDavid du Colombier static Regs regs[] = {
37072cfc098SDavid du Colombier // "Par0", Par0, 1,
37172cfc098SDavid du Colombier // "Par1", Par0+1, 1,
37272cfc098SDavid du Colombier // "Par2", Par0+2, 1,
37372cfc098SDavid du Colombier // "Par3", Par0+3, 1,
37472cfc098SDavid du Colombier // "Par4", Par0+4, 1,
37572cfc098SDavid du Colombier // "Par5", Par0+5, 1,
37672cfc098SDavid du Colombier "Rcr", Rcr, 1,
37772cfc098SDavid du Colombier "Tcr", Tcr, 1,
37872cfc098SDavid du Colombier "Cr0", Cr, 1,
37972cfc098SDavid du Colombier "Cr1", Cr+1, 1,
38072cfc098SDavid du Colombier "Isr0", Isr, 1,
38172cfc098SDavid du Colombier "Isr1", Isr+1, 1,
38272cfc098SDavid du Colombier "Imr0", Imr, 1,
38372cfc098SDavid du Colombier "Imr1", Imr+1, 1,
38472cfc098SDavid du Colombier // "Mcfilt0", Mcfilt0,4,
38572cfc098SDavid du Colombier // "Mcfilt1", Mcfilt1,4,
38672cfc098SDavid du Colombier // "Rxdaddr", Rxdaddr,4,
38772cfc098SDavid du Colombier // "Txdaddr", Txdaddr,4,
38872cfc098SDavid du Colombier "Phyadr", Phyadr, 1,
38972cfc098SDavid du Colombier "Miisr", Miisr, 1,
39072cfc098SDavid du Colombier "Bcr0", Bcr0, 1,
39172cfc098SDavid du Colombier "Bcr1", Bcr1, 1,
39272cfc098SDavid du Colombier "Miicr", Miicr, 1,
39372cfc098SDavid du Colombier "Miiadr", Miiadr, 1,
39472cfc098SDavid du Colombier // "Miidata", Miidata,2,
39572cfc098SDavid du Colombier "Eecsr", Eecsr, 1,
39672cfc098SDavid du Colombier "CfgA", CfgA, 1,
39772cfc098SDavid du Colombier "CfgB", CfgB, 1,
39872cfc098SDavid du Colombier "CfgC", CfgC, 1,
39972cfc098SDavid du Colombier "CfgD", CfgD, 1,
40072cfc098SDavid du Colombier "Cr0", Cr0, 1,
40172cfc098SDavid du Colombier "Cr1", Cr1, 1,
40272cfc098SDavid du Colombier "Pmcc", Pmcc, 1,
40372cfc098SDavid du Colombier "Stickhw", Stickhw,1,
40472cfc098SDavid du Colombier "Misr", Misr, 1,
40572cfc098SDavid du Colombier "Mimr", Mimr, 1,
40672cfc098SDavid du Colombier nil,
40772cfc098SDavid du Colombier };
40872cfc098SDavid du Colombier
40972cfc098SDavid du Colombier static char* rxstats[Nrxstats] = {
41072cfc098SDavid du Colombier "Receiver Error",
41172cfc098SDavid du Colombier "CRC Error",
41272cfc098SDavid du Colombier "Frame Alignment Error",
41372cfc098SDavid du Colombier "FIFO Overflow",
41472cfc098SDavid du Colombier "Long Packet",
41572cfc098SDavid du Colombier "Runt Packet",
41672cfc098SDavid du Colombier "System Error",
41772cfc098SDavid du Colombier "Buffer Underflow Error",
41872cfc098SDavid du Colombier };
41972cfc098SDavid du Colombier static char* txstats[Ntxstats] = {
42072cfc098SDavid du Colombier "Aborted after Excessive Collisions",
42172cfc098SDavid du Colombier "Out of Window Collision Seen",
42272cfc098SDavid du Colombier "Carrier Sense Lost",
42372cfc098SDavid du Colombier "FIFO Underflow",
42472cfc098SDavid du Colombier "Invalid Td",
42572cfc098SDavid du Colombier "System Error",
42672cfc098SDavid du Colombier nil,
42772cfc098SDavid du Colombier "Excessive Collisions",
42872cfc098SDavid du Colombier };
42972cfc098SDavid du Colombier
43072cfc098SDavid du Colombier static long
vt6105Mifstat(Ether * edev,void * a,long n,ulong offset)43172cfc098SDavid du Colombier vt6105Mifstat(Ether* edev, void* a, long n, ulong offset)
43272cfc098SDavid du Colombier {
43372cfc098SDavid du Colombier int i, r;
43472cfc098SDavid du Colombier Ctlr *ctlr;
43572cfc098SDavid du Colombier char *alloc, *e, *p;
43672cfc098SDavid du Colombier
43772cfc098SDavid du Colombier ctlr = edev->ctlr;
43872cfc098SDavid du Colombier
43946136019SDavid du Colombier alloc = malloc(READSTR);
44072cfc098SDavid du Colombier p = alloc;
441aa72973aSDavid du Colombier if(p == nil)
442aa72973aSDavid du Colombier error(Enomem);
44346136019SDavid du Colombier e = p + READSTR;
44472cfc098SDavid du Colombier for(i = 0; i < Nrxstats; i++){
44572cfc098SDavid du Colombier p = seprint(p, e, "%s: %ud\n", rxstats[i], ctlr->rxstats[i]);
44672cfc098SDavid du Colombier }
44772cfc098SDavid du Colombier for(i = 0; i < Ntxstats; i++){
44872cfc098SDavid du Colombier if(txstats[i] == nil)
44972cfc098SDavid du Colombier continue;
45072cfc098SDavid du Colombier p = seprint(p, e, "%s: %ud\n", txstats[i], ctlr->txstats[i]);
45172cfc098SDavid du Colombier }
45272cfc098SDavid du Colombier p = seprint(p, e, "cls: %ud\n", ctlr->cls);
45372cfc098SDavid du Colombier p = seprint(p, e, "intr: %ud\n", ctlr->intr);
45472cfc098SDavid du Colombier p = seprint(p, e, "lintr: %ud\n", ctlr->lintr);
45572cfc098SDavid du Colombier p = seprint(p, e, "lsleep: %ud\n", ctlr->lsleep);
45672cfc098SDavid du Colombier p = seprint(p, e, "rintr: %ud\n", ctlr->rintr);
45772cfc098SDavid du Colombier p = seprint(p, e, "tintr: %ud\n", ctlr->tintr);
45872cfc098SDavid du Colombier p = seprint(p, e, "txdw: %ud\n", ctlr->txdw);
45972cfc098SDavid du Colombier p = seprint(p, e, "tdumax: %ud\n", ctlr->tdumax);
46072cfc098SDavid du Colombier p = seprint(p, e, "tft: %ud\n", ctlr->tft);
46172cfc098SDavid du Colombier
46272cfc098SDavid du Colombier p = seprint(p, e, "abt: %ud\n", ctlr->abt);
46372cfc098SDavid du Colombier p = seprint(p, e, "tbuff: %ud\n", ctlr->tbuff);
46472cfc098SDavid du Colombier p = seprint(p, e, "udf: %ud\n", ctlr->udf);
46572cfc098SDavid du Colombier p = seprint(p, e, "abti: %ud\n", ctlr->abti);
46672cfc098SDavid du Colombier p = seprint(p, e, "udfi: %ud\n", ctlr->udfi);
46772cfc098SDavid du Colombier p = seprint(p, e, "tu: %ud\n", ctlr->tu);
46872cfc098SDavid du Colombier
46972cfc098SDavid du Colombier p = seprint(p, e, "tuok: %ud\n", ctlr->tuok);
47072cfc098SDavid du Colombier p = seprint(p, e, "ipok: %ud\n", ctlr->ipok);
47172cfc098SDavid du Colombier
47272cfc098SDavid du Colombier p = seprint(p, e, "rbpoolsz: %ud\n", vt6105Mrbpoolsz);
47372cfc098SDavid du Colombier p = seprint(p, e, "totalt: %uld\n", ctlr->totalt);
47472cfc098SDavid du Colombier
47572cfc098SDavid du Colombier for(i = 0; regs[i].name != nil; i++){
47672cfc098SDavid du Colombier p = seprint(p, e, "%s: %2.2x\n",
47772cfc098SDavid du Colombier regs[i].name, csr8r(ctlr, regs[i].offset));
47872cfc098SDavid du Colombier }
47972cfc098SDavid du Colombier
48072cfc098SDavid du Colombier if(ctlr->mii != nil && ctlr->mii->curphy != nil){
48172cfc098SDavid du Colombier p = seprint(p, e, "phy: ");
48272cfc098SDavid du Colombier for(i = 0; i < NMiiPhyr; i++){
48372cfc098SDavid du Colombier if(i && ((i & 0x07) == 0))
48472cfc098SDavid du Colombier p = seprint(p, e, "\n ");
48572cfc098SDavid du Colombier r = miimir(ctlr->mii, i);
48672cfc098SDavid du Colombier p = seprint(p, e, " %4.4uX", r);
48772cfc098SDavid du Colombier }
48872cfc098SDavid du Colombier seprint(p, e, "\n");
48972cfc098SDavid du Colombier }
49072cfc098SDavid du Colombier
49172cfc098SDavid du Colombier n = readstr(offset, a, n, alloc);
49272cfc098SDavid du Colombier free(alloc);
49372cfc098SDavid du Colombier
49472cfc098SDavid du Colombier return n;
49572cfc098SDavid du Colombier }
49672cfc098SDavid du Colombier
49772cfc098SDavid du Colombier static void
vt6105Mpromiscuous(void * arg,int on)49872cfc098SDavid du Colombier vt6105Mpromiscuous(void* arg, int on)
49972cfc098SDavid du Colombier {
50072cfc098SDavid du Colombier int rcr;
50172cfc098SDavid du Colombier Ctlr *ctlr;
50272cfc098SDavid du Colombier Ether *edev;
50372cfc098SDavid du Colombier
50472cfc098SDavid du Colombier edev = arg;
50572cfc098SDavid du Colombier ctlr = edev->ctlr;
50672cfc098SDavid du Colombier rcr = csr8r(ctlr, Rcr);
50772cfc098SDavid du Colombier if(on)
50872cfc098SDavid du Colombier rcr |= Prom;
50972cfc098SDavid du Colombier else
51072cfc098SDavid du Colombier rcr &= ~Prom;
51172cfc098SDavid du Colombier csr8w(ctlr, Rcr, rcr);
51272cfc098SDavid du Colombier }
51372cfc098SDavid du Colombier
51472cfc098SDavid du Colombier static void
vt6105Mmulticast(void * arg,uchar * addr,int on)51572cfc098SDavid du Colombier vt6105Mmulticast(void* arg, uchar* addr, int on)
51672cfc098SDavid du Colombier {
51772cfc098SDavid du Colombier /*
51872cfc098SDavid du Colombier * For now Am is set in Rcr.
51972cfc098SDavid du Colombier * Will need to interlock with promiscuous
52072cfc098SDavid du Colombier * when this gets filled in.
52172cfc098SDavid du Colombier */
52272cfc098SDavid du Colombier USED(arg, addr, on);
52372cfc098SDavid du Colombier }
52472cfc098SDavid du Colombier
52572cfc098SDavid du Colombier static int
vt6105Mwakeup(void * v)52672cfc098SDavid du Colombier vt6105Mwakeup(void* v)
52772cfc098SDavid du Colombier {
52872cfc098SDavid du Colombier return *((int*)v) != 0;
52972cfc098SDavid du Colombier }
53072cfc098SDavid du Colombier
53172cfc098SDavid du Colombier static void
vt6105Mimr(Ctlr * ctlr,int imr)53272cfc098SDavid du Colombier vt6105Mimr(Ctlr* ctlr, int imr)
53372cfc098SDavid du Colombier {
53472cfc098SDavid du Colombier ilock(&ctlr->clock);
53572cfc098SDavid du Colombier ctlr->imr |= imr;
53672cfc098SDavid du Colombier csr16w(ctlr, Imr, ctlr->imr);
53772cfc098SDavid du Colombier iunlock(&ctlr->clock);
53872cfc098SDavid du Colombier }
53972cfc098SDavid du Colombier
54072cfc098SDavid du Colombier static void
vt6105Mlproc(void * arg)54172cfc098SDavid du Colombier vt6105Mlproc(void* arg)
54272cfc098SDavid du Colombier {
54372cfc098SDavid du Colombier Ctlr *ctlr;
54472cfc098SDavid du Colombier Ether *edev;
54572cfc098SDavid du Colombier MiiPhy *phy;
54672cfc098SDavid du Colombier
54772cfc098SDavid du Colombier edev = arg;
54872cfc098SDavid du Colombier ctlr = edev->ctlr;
54972cfc098SDavid du Colombier for(;;){
55072cfc098SDavid du Colombier if(ctlr->mii == nil || ctlr->mii->curphy == nil)
55172cfc098SDavid du Colombier break;
55272cfc098SDavid du Colombier if(miistatus(ctlr->mii) < 0)
55372cfc098SDavid du Colombier goto enable;
55472cfc098SDavid du Colombier
55572cfc098SDavid du Colombier phy = ctlr->mii->curphy;
55672cfc098SDavid du Colombier ilock(&ctlr->clock);
55772cfc098SDavid du Colombier csr16w(ctlr, Cr, ctlr->cr & ~(Txon|Rxon));
55872cfc098SDavid du Colombier if(phy->fd)
55972cfc098SDavid du Colombier ctlr->cr |= Fdx;
56072cfc098SDavid du Colombier else
56172cfc098SDavid du Colombier ctlr->cr &= ~Fdx;
56272cfc098SDavid du Colombier csr16w(ctlr, Cr, ctlr->cr);
56372cfc098SDavid du Colombier iunlock(&ctlr->clock);
56472cfc098SDavid du Colombier enable:
56572cfc098SDavid du Colombier ctlr->lwakeup = 0;
56672cfc098SDavid du Colombier vt6105Mimr(ctlr, Srci);
56772cfc098SDavid du Colombier
56872cfc098SDavid du Colombier ctlr->lsleep++;
56972cfc098SDavid du Colombier sleep(&ctlr->lrendez, vt6105Mwakeup, &ctlr->lwakeup);
57072cfc098SDavid du Colombier
57172cfc098SDavid du Colombier }
57272cfc098SDavid du Colombier pexit("vt6105Mlproc: done", 1);
57372cfc098SDavid du Colombier }
57472cfc098SDavid du Colombier
57572cfc098SDavid du Colombier static void
vt6105Mrbfree(Block * bp)57672cfc098SDavid du Colombier vt6105Mrbfree(Block* bp)
57772cfc098SDavid du Colombier {
57872cfc098SDavid du Colombier bp->rp = bp->lim - (Rdbsz+3);
57972cfc098SDavid du Colombier bp->wp = bp->rp;
580bfb6eab9SDavid du Colombier bp->flag &= ~(Bipck | Budpck | Btcpck | Bpktck);
58172cfc098SDavid du Colombier
58272cfc098SDavid du Colombier ilock(&vt6105Mrblock);
58372cfc098SDavid du Colombier bp->next = vt6105Mrbpool;
58472cfc098SDavid du Colombier vt6105Mrbpool = bp;
58572cfc098SDavid du Colombier iunlock(&vt6105Mrblock);
58672cfc098SDavid du Colombier }
58772cfc098SDavid du Colombier
58872cfc098SDavid du Colombier static Block*
vt6105Mrballoc(void)58972cfc098SDavid du Colombier vt6105Mrballoc(void)
59072cfc098SDavid du Colombier {
59172cfc098SDavid du Colombier Block *bp;
59272cfc098SDavid du Colombier
59372cfc098SDavid du Colombier ilock(&vt6105Mrblock);
59472cfc098SDavid du Colombier if((bp = vt6105Mrbpool) != nil){
59572cfc098SDavid du Colombier vt6105Mrbpool = bp->next;
59672cfc098SDavid du Colombier bp->next = nil;
59772cfc098SDavid du Colombier _xinc(&bp->ref); /* prevent bp from being freed */
59872cfc098SDavid du Colombier }
59972cfc098SDavid du Colombier iunlock(&vt6105Mrblock);
60072cfc098SDavid du Colombier
60172cfc098SDavid du Colombier if(bp == nil && (bp = iallocb(Rdbsz+3)) != nil){
60272cfc098SDavid du Colombier bp->free = vt6105Mrbfree;
60372cfc098SDavid du Colombier vt6105Mrbpoolsz++;
60472cfc098SDavid du Colombier }
60572cfc098SDavid du Colombier return bp;
60672cfc098SDavid du Colombier }
60772cfc098SDavid du Colombier
60872cfc098SDavid du Colombier static void
vt6105Mattach(Ether * edev)60972cfc098SDavid du Colombier vt6105Mattach(Ether* edev)
61072cfc098SDavid du Colombier {
61172cfc098SDavid du Colombier Ctlr *ctlr;
61272cfc098SDavid du Colombier // MiiPhy *phy;
61372cfc098SDavid du Colombier uchar *alloc;
61472cfc098SDavid du Colombier Ds *ds, *prev;
61572cfc098SDavid du Colombier int dsz, i, timeo;
61672cfc098SDavid du Colombier char name[KNAMELEN];
61772cfc098SDavid du Colombier
61872cfc098SDavid du Colombier ctlr = edev->ctlr;
61972cfc098SDavid du Colombier qlock(&ctlr->alock);
62072cfc098SDavid du Colombier if(ctlr->alloc != nil){
62172cfc098SDavid du Colombier qunlock(&ctlr->alock);
62272cfc098SDavid du Colombier return;
62372cfc098SDavid du Colombier }
62472cfc098SDavid du Colombier
62572cfc098SDavid du Colombier /*
62672cfc098SDavid du Colombier * Descriptor space.
62772cfc098SDavid du Colombier * Receive descriptors should all be aligned on a 4-byte boundary,
62872cfc098SDavid du Colombier * but try to do cache-line alignment.
62972cfc098SDavid du Colombier */
63072cfc098SDavid du Colombier ctlr->nrd = Nrd;
63172cfc098SDavid du Colombier ctlr->ntd = Ntd;
63272cfc098SDavid du Colombier dsz = ROUNDUP(sizeof(Ds), ctlr->cls);
63372cfc098SDavid du Colombier alloc = mallocalign((ctlr->nrd+ctlr->ntd)*dsz, dsz, 0, 0);
63472cfc098SDavid du Colombier if(alloc == nil){
63572cfc098SDavid du Colombier qunlock(&ctlr->alock);
6366fbfa2f3SDavid du Colombier error(Enomem);
63772cfc098SDavid du Colombier }
63872cfc098SDavid du Colombier ctlr->alloc = alloc;
63972cfc098SDavid du Colombier
64072cfc098SDavid du Colombier ctlr->rd = (Ds*)alloc;
64172cfc098SDavid du Colombier
64272cfc098SDavid du Colombier if(waserror()){
64372cfc098SDavid du Colombier ds = ctlr->rd;
64472cfc098SDavid du Colombier for(i = 0; i < ctlr->nrd; i++){
64572cfc098SDavid du Colombier if(ds->bp != nil){
64672cfc098SDavid du Colombier freeb(ds->bp);
64772cfc098SDavid du Colombier ds->bp = nil;
64872cfc098SDavid du Colombier }
64972cfc098SDavid du Colombier if((ds = ds->next) == nil)
65072cfc098SDavid du Colombier break;
65172cfc098SDavid du Colombier }
65272cfc098SDavid du Colombier free(ctlr->alloc);
65372cfc098SDavid du Colombier ctlr->alloc = nil;
65472cfc098SDavid du Colombier qunlock(&ctlr->alock);
65572cfc098SDavid du Colombier nexterror();
65672cfc098SDavid du Colombier }
65772cfc098SDavid du Colombier
65872cfc098SDavid du Colombier prev = (Ds*)(alloc + (ctlr->nrd-1)*dsz);
65972cfc098SDavid du Colombier for(i = 0; i < ctlr->nrd; i++){
66072cfc098SDavid du Colombier ds = (Ds*)alloc;
66172cfc098SDavid du Colombier alloc += dsz;
66272cfc098SDavid du Colombier
66372cfc098SDavid du Colombier ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
66472cfc098SDavid du Colombier ds->branch = PCIWADDR(alloc);
66572cfc098SDavid du Colombier
66672cfc098SDavid du Colombier ds->bp = vt6105Mrballoc();
66772cfc098SDavid du Colombier if(ds->bp == nil)
66872cfc098SDavid du Colombier error("vt6105M: can't allocate receive ring\n");
66972cfc098SDavid du Colombier ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4);
67072cfc098SDavid du Colombier ds->addr = PCIWADDR(ds->bp->rp);
67172cfc098SDavid du Colombier
67272cfc098SDavid du Colombier ds->next = (Ds*)alloc;
67372cfc098SDavid du Colombier ds->prev = prev;
67472cfc098SDavid du Colombier prev = ds;
67572cfc098SDavid du Colombier
67672cfc098SDavid du Colombier ds->status = Own;
67772cfc098SDavid du Colombier }
67872cfc098SDavid du Colombier prev->branch = 0;
67972cfc098SDavid du Colombier prev->next = ctlr->rd;
68072cfc098SDavid du Colombier prev->status = 0;
68172cfc098SDavid du Colombier ctlr->rdh = ctlr->rd;
68272cfc098SDavid du Colombier
68372cfc098SDavid du Colombier ctlr->td = (Ds*)alloc;
68472cfc098SDavid du Colombier prev = (Ds*)(alloc + (ctlr->ntd-1)*dsz);
68572cfc098SDavid du Colombier for(i = 0; i < ctlr->ntd; i++){
68672cfc098SDavid du Colombier ds = (Ds*)alloc;
68772cfc098SDavid du Colombier alloc += dsz;
68872cfc098SDavid du Colombier
68972cfc098SDavid du Colombier ds->next = (Ds*)alloc;
69072cfc098SDavid du Colombier ds->prev = prev;
69172cfc098SDavid du Colombier prev = ds;
69272cfc098SDavid du Colombier }
69372cfc098SDavid du Colombier prev->next = ctlr->td;
69472cfc098SDavid du Colombier ctlr->tdh = ctlr->tdt = ctlr->td;
69572cfc098SDavid du Colombier ctlr->tdused = 0;
69672cfc098SDavid du Colombier
69772cfc098SDavid du Colombier ctlr->cr = Dpoll|Rdmd/*|Txon|Rxon*/|Strt;
69872cfc098SDavid du Colombier /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/
69972cfc098SDavid du Colombier ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx;
70072cfc098SDavid du Colombier
70172cfc098SDavid du Colombier ilock(&ctlr->clock);
70272cfc098SDavid du Colombier csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd));
70372cfc098SDavid du Colombier csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td));
70472cfc098SDavid du Colombier csr16w(ctlr, Isr, ~0);
70572cfc098SDavid du Colombier csr16w(ctlr, Imr, ctlr->imr);
70672cfc098SDavid du Colombier csr16w(ctlr, Cr, ctlr->cr);
70772cfc098SDavid du Colombier iunlock(&ctlr->clock);
70872cfc098SDavid du Colombier
70972cfc098SDavid du Colombier /*
71072cfc098SDavid du Colombier * Wait for link to be ready.
71172cfc098SDavid du Colombier */
71272cfc098SDavid du Colombier for(timeo = 0; timeo < 350; timeo++){
71372cfc098SDavid du Colombier if(miistatus(ctlr->mii) == 0)
71472cfc098SDavid du Colombier break;
71572cfc098SDavid du Colombier tsleep(&up->sleep, return0, 0, 10);
71672cfc098SDavid du Colombier }
71772cfc098SDavid du Colombier // phy = ctlr->mii->curphy;
71872cfc098SDavid du Colombier // print("%s: speed %d fd %d link %d rfc %d tfc %d\n",
71972cfc098SDavid du Colombier // edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc);
72072cfc098SDavid du Colombier
72172cfc098SDavid du Colombier ilock(&ctlr->clock);
72272cfc098SDavid du Colombier ctlr->cr |= Txon|Rxon;
72372cfc098SDavid du Colombier csr16w(ctlr, Cr, ctlr->cr);
72472cfc098SDavid du Colombier iunlock(&ctlr->clock);
72572cfc098SDavid du Colombier
72672cfc098SDavid du Colombier snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
72772cfc098SDavid du Colombier kproc(name, vt6105Mlproc, edev);
72872cfc098SDavid du Colombier
72972cfc098SDavid du Colombier qunlock(&ctlr->alock);
73072cfc098SDavid du Colombier poperror();
73172cfc098SDavid du Colombier }
73272cfc098SDavid du Colombier
73372cfc098SDavid du Colombier static void
vt6105Mtransmit(Ether * edev)73472cfc098SDavid du Colombier vt6105Mtransmit(Ether* edev)
73572cfc098SDavid du Colombier {
73672cfc098SDavid du Colombier Block *bp;
73772cfc098SDavid du Colombier Ctlr *ctlr;
73872cfc098SDavid du Colombier Ds *ds, *next;
73972cfc098SDavid du Colombier int control, i, size, tdused, timeo;
74072cfc098SDavid du Colombier long t;
74172cfc098SDavid du Colombier
74272cfc098SDavid du Colombier ctlr = edev->ctlr;
74372cfc098SDavid du Colombier
74472cfc098SDavid du Colombier ilock(&ctlr->tlock);
74572cfc098SDavid du Colombier t = lcycles();
74672cfc098SDavid du Colombier
74772cfc098SDavid du Colombier /*
74872cfc098SDavid du Colombier * Free any completed packets
74972cfc098SDavid du Colombier */
75072cfc098SDavid du Colombier ds = ctlr->tdh;
75172cfc098SDavid du Colombier for(tdused = ctlr->tdused; tdused > 0; tdused--){
75272cfc098SDavid du Colombier /*
75372cfc098SDavid du Colombier * For some errors the chip will turn the Tx engine
75472cfc098SDavid du Colombier * off. Wait for that to happen.
75572cfc098SDavid du Colombier * Could reset and re-init the chip here if it doesn't
75672cfc098SDavid du Colombier * play fair.
75772cfc098SDavid du Colombier * To do: adjust Tx FIFO threshold on underflow.
75872cfc098SDavid du Colombier */
75972cfc098SDavid du Colombier if(ds->status & (Abt|Tbuff|Udf)){
76072cfc098SDavid du Colombier if(ds->status & Abt)
76172cfc098SDavid du Colombier ctlr->abt++;
76272cfc098SDavid du Colombier if(ds->status & Tbuff)
76372cfc098SDavid du Colombier ctlr->tbuff++;
76472cfc098SDavid du Colombier if(ds->status & Udf)
76572cfc098SDavid du Colombier ctlr->udf++;
76672cfc098SDavid du Colombier for(timeo = 0; timeo < 1000; timeo++){
76772cfc098SDavid du Colombier if(!(csr16r(ctlr, Cr) & Txon))
76872cfc098SDavid du Colombier break;
76972cfc098SDavid du Colombier microdelay(1);
77072cfc098SDavid du Colombier }
77172cfc098SDavid du Colombier ds->status = Own;
77272cfc098SDavid du Colombier csr32w(ctlr, Txdaddr, PCIWADDR(ds));
77372cfc098SDavid du Colombier }
77472cfc098SDavid du Colombier
77572cfc098SDavid du Colombier if(ds->status & Own)
77672cfc098SDavid du Colombier break;
77772cfc098SDavid du Colombier ds->addr = 0;
77872cfc098SDavid du Colombier ds->branch = 0;
77972cfc098SDavid du Colombier
78072cfc098SDavid du Colombier if(ds->bp != nil){
78172cfc098SDavid du Colombier freeb(ds->bp);
78272cfc098SDavid du Colombier ds->bp = nil;
78372cfc098SDavid du Colombier }
78472cfc098SDavid du Colombier for(i = 0; i < Ntxstats-1; i++){
78572cfc098SDavid du Colombier if(ds->status & (1<<i))
78672cfc098SDavid du Colombier ctlr->txstats[i]++;
78772cfc098SDavid du Colombier }
78872cfc098SDavid du Colombier ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT;
78972cfc098SDavid du Colombier
79072cfc098SDavid du Colombier ds = ds->next;
79172cfc098SDavid du Colombier }
79272cfc098SDavid du Colombier ctlr->tdh = ds;
79372cfc098SDavid du Colombier
79472cfc098SDavid du Colombier /*
79572cfc098SDavid du Colombier * Try to fill the ring back up.
79672cfc098SDavid du Colombier */
79772cfc098SDavid du Colombier ds = ctlr->tdt;
79872cfc098SDavid du Colombier while(tdused < ctlr->ntd-2){
79972cfc098SDavid du Colombier if((bp = qget(edev->oq)) == nil)
80072cfc098SDavid du Colombier break;
80172cfc098SDavid du Colombier tdused++;
80272cfc098SDavid du Colombier
80372cfc098SDavid du Colombier size = BLEN(bp);
80472cfc098SDavid du Colombier
80572cfc098SDavid du Colombier next = ds->next;
80672cfc098SDavid du Colombier ds->branch = PCIWADDR(ds->next)|Tdctl;
80772cfc098SDavid du Colombier
80872cfc098SDavid du Colombier ds->bp = bp;
80972cfc098SDavid du Colombier ds->addr = PCIWADDR(bp->rp);
81072cfc098SDavid du Colombier control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK);
81172cfc098SDavid du Colombier
81272cfc098SDavid du Colombier ds->control = control;
81372cfc098SDavid du Colombier if(tdused >= ctlr->ntd-2){
81472cfc098SDavid du Colombier ctlr->txdw++;
81572cfc098SDavid du Colombier ds->branch &= ~Tdctl;
81672cfc098SDavid du Colombier }
81772cfc098SDavid du Colombier coherence();
81872cfc098SDavid du Colombier ds->status = Own;
81972cfc098SDavid du Colombier
82072cfc098SDavid du Colombier ds = next;
82172cfc098SDavid du Colombier }
82272cfc098SDavid du Colombier ctlr->tdt = ds;
82372cfc098SDavid du Colombier ctlr->tdused = tdused;
82472cfc098SDavid du Colombier if(ctlr->tdused){
82572cfc098SDavid du Colombier csr16w(ctlr, Cr, Tdmd|ctlr->cr);
82672cfc098SDavid du Colombier if(tdused > ctlr->tdumax)
82772cfc098SDavid du Colombier ctlr->tdumax = tdused;
82872cfc098SDavid du Colombier }
82972cfc098SDavid du Colombier
83072cfc098SDavid du Colombier ctlr->totalt += lcycles() - t;
83172cfc098SDavid du Colombier iunlock(&ctlr->tlock);
83272cfc098SDavid du Colombier }
83372cfc098SDavid du Colombier
83472cfc098SDavid du Colombier static void
vt6105Mreceive(Ether * edev)83572cfc098SDavid du Colombier vt6105Mreceive(Ether* edev)
83672cfc098SDavid du Colombier {
83772cfc098SDavid du Colombier Ds *ds;
83872cfc098SDavid du Colombier Block *bp;
83972cfc098SDavid du Colombier Ctlr *ctlr;
84072cfc098SDavid du Colombier int i, len;
84172cfc098SDavid du Colombier
84272cfc098SDavid du Colombier ctlr = edev->ctlr;
84372cfc098SDavid du Colombier
84472cfc098SDavid du Colombier ds = ctlr->rdh;
84572cfc098SDavid du Colombier while(!(ds->status & Own) && ds->status != 0){
84672cfc098SDavid du Colombier /*
84772cfc098SDavid du Colombier * Can Long packets be received OK?
84872cfc098SDavid du Colombier * What happens to the Rxok bit?
84972cfc098SDavid du Colombier */
85072cfc098SDavid du Colombier if(ds->status & Rerr){
85172cfc098SDavid du Colombier for(i = 0; i < Nrxstats; i++){
85272cfc098SDavid du Colombier if(ds->status & (1<<i))
85372cfc098SDavid du Colombier ctlr->rxstats[i]++;
85472cfc098SDavid du Colombier }
85572cfc098SDavid du Colombier }
85672cfc098SDavid du Colombier else if(bp = vt6105Mrballoc()){
85772cfc098SDavid du Colombier if(ds->control & Tuok){
85872cfc098SDavid du Colombier ds->bp->flag |= Btcpck|Budpck;
85972cfc098SDavid du Colombier ctlr->tuok++;
86072cfc098SDavid du Colombier }
86172cfc098SDavid du Colombier if(ds->control & Ipok){
86272cfc098SDavid du Colombier ds->bp->flag |= Bipck;
86372cfc098SDavid du Colombier ctlr->ipok++;
86472cfc098SDavid du Colombier }
86572cfc098SDavid du Colombier len = ((ds->status & LengthMASK)>>LengthSHIFT)-4;
86672cfc098SDavid du Colombier ds->bp->wp = ds->bp->rp+len;
86772cfc098SDavid du Colombier etheriq(edev, ds->bp, 1);
86872cfc098SDavid du Colombier bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4);
86972cfc098SDavid du Colombier ds->addr = PCIWADDR(bp->rp);
87072cfc098SDavid du Colombier ds->bp = bp;
87172cfc098SDavid du Colombier }
87272cfc098SDavid du Colombier ds->control = Ipkt|Tcpkt|Udpkt|Rdbsz;
87372cfc098SDavid du Colombier ds->branch = 0;
87472cfc098SDavid du Colombier ds->status = 0;
87572cfc098SDavid du Colombier
87672cfc098SDavid du Colombier ds->prev->branch = PCIWADDR(ds);
87772cfc098SDavid du Colombier coherence();
87872cfc098SDavid du Colombier ds->prev->status = Own;
87972cfc098SDavid du Colombier
88072cfc098SDavid du Colombier ds = ds->next;
88172cfc098SDavid du Colombier }
88272cfc098SDavid du Colombier ctlr->rdh = ds;
88372cfc098SDavid du Colombier
88472cfc098SDavid du Colombier csr16w(ctlr, Cr, ctlr->cr);
88572cfc098SDavid du Colombier }
88672cfc098SDavid du Colombier
88772cfc098SDavid du Colombier static void
vt6105Minterrupt(Ureg *,void * arg)88872cfc098SDavid du Colombier vt6105Minterrupt(Ureg*, void* arg)
88972cfc098SDavid du Colombier {
89072cfc098SDavid du Colombier Ctlr *ctlr;
89172cfc098SDavid du Colombier Ether *edev;
89272cfc098SDavid du Colombier int imr, isr, r, timeo;
89372cfc098SDavid du Colombier long t;
89472cfc098SDavid du Colombier
89572cfc098SDavid du Colombier edev = arg;
89672cfc098SDavid du Colombier ctlr = edev->ctlr;
89772cfc098SDavid du Colombier
89872cfc098SDavid du Colombier ilock(&ctlr->clock);
89972cfc098SDavid du Colombier t = lcycles();
90072cfc098SDavid du Colombier
90172cfc098SDavid du Colombier csr16w(ctlr, Imr, 0);
90272cfc098SDavid du Colombier imr = ctlr->imr;
90372cfc098SDavid du Colombier ctlr->intr++;
90472cfc098SDavid du Colombier for(;;){
90572cfc098SDavid du Colombier if((isr = csr16r(ctlr, Isr)) != 0)
90672cfc098SDavid du Colombier csr16w(ctlr, Isr, isr);
90772cfc098SDavid du Colombier if((isr & ctlr->imr) == 0)
90872cfc098SDavid du Colombier break;
90972cfc098SDavid du Colombier
91072cfc098SDavid du Colombier if(isr & Srci){
91172cfc098SDavid du Colombier imr &= ~Srci;
91272cfc098SDavid du Colombier ctlr->lwakeup = isr & Srci;
91372cfc098SDavid du Colombier wakeup(&ctlr->lrendez);
91472cfc098SDavid du Colombier isr &= ~Srci;
91572cfc098SDavid du Colombier ctlr->lintr++;
91672cfc098SDavid du Colombier }
91772cfc098SDavid du Colombier if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){
91872cfc098SDavid du Colombier vt6105Mreceive(edev);
91972cfc098SDavid du Colombier isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx);
92072cfc098SDavid du Colombier ctlr->rintr++;
92172cfc098SDavid du Colombier }
92272cfc098SDavid du Colombier if(isr & (Abti|Udfi|Tu|Txe|Ptx)){
92372cfc098SDavid du Colombier if(isr & (Abti|Udfi|Tu)){
92472cfc098SDavid du Colombier if(isr & Abti)
92572cfc098SDavid du Colombier ctlr->abti++;
92672cfc098SDavid du Colombier if(isr & Udfi)
92772cfc098SDavid du Colombier ctlr->udfi++;
92872cfc098SDavid du Colombier if(isr & Tu)
92972cfc098SDavid du Colombier ctlr->tu++;
93072cfc098SDavid du Colombier for(timeo = 0; timeo < 1000; timeo++){
93172cfc098SDavid du Colombier if(!(csr16r(ctlr, Cr) & Txon))
93272cfc098SDavid du Colombier break;
93372cfc098SDavid du Colombier microdelay(1);
93472cfc098SDavid du Colombier }
93572cfc098SDavid du Colombier
93672cfc098SDavid du Colombier if((isr & Udfi) && ctlr->tft < CtftSAF){
93772cfc098SDavid du Colombier ctlr->tft += 1<<CtftSHIFT;
93872cfc098SDavid du Colombier r = csr8r(ctlr, Bcr1) & ~CtftMASK;
93972cfc098SDavid du Colombier csr8w(ctlr, Bcr1, r|ctlr->tft);
94072cfc098SDavid du Colombier }
94172cfc098SDavid du Colombier }
94272cfc098SDavid du Colombier
94372cfc098SDavid du Colombier
94472cfc098SDavid du Colombier ctlr->totalt += lcycles() - t;
94572cfc098SDavid du Colombier vt6105Mtransmit(edev);
94672cfc098SDavid du Colombier t = lcycles();
94772cfc098SDavid du Colombier isr &= ~(Abti|Udfi|Tu|Txe|Ptx);
94872cfc098SDavid du Colombier ctlr->tintr++;
94972cfc098SDavid du Colombier }
95072cfc098SDavid du Colombier if(isr)
95172cfc098SDavid du Colombier panic("vt6105M: isr %4.4uX\n", isr);
95272cfc098SDavid du Colombier }
95372cfc098SDavid du Colombier ctlr->imr = imr;
95472cfc098SDavid du Colombier csr16w(ctlr, Imr, ctlr->imr);
95572cfc098SDavid du Colombier
95672cfc098SDavid du Colombier ctlr->totalt += lcycles() - t;
95772cfc098SDavid du Colombier iunlock(&ctlr->clock);
95872cfc098SDavid du Colombier }
95972cfc098SDavid du Colombier
96072cfc098SDavid du Colombier static int
vt6105Mmiimicmd(Mii * mii,int pa,int ra,int cmd,int data)96172cfc098SDavid du Colombier vt6105Mmiimicmd(Mii* mii, int pa, int ra, int cmd, int data)
96272cfc098SDavid du Colombier {
96372cfc098SDavid du Colombier Ctlr *ctlr;
96472cfc098SDavid du Colombier int r, timeo;
96572cfc098SDavid du Colombier
96672cfc098SDavid du Colombier ctlr = mii->ctlr;
96772cfc098SDavid du Colombier
96872cfc098SDavid du Colombier csr8w(ctlr, Miicr, 0);
96972cfc098SDavid du Colombier r = csr8r(ctlr, Phyadr);
97072cfc098SDavid du Colombier csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa);
97172cfc098SDavid du Colombier csr8w(ctlr, Phyadr, pa);
97272cfc098SDavid du Colombier csr8w(ctlr, Miiadr, ra);
97372cfc098SDavid du Colombier if(cmd == Wcmd)
97472cfc098SDavid du Colombier csr16w(ctlr, Miidata, data);
97572cfc098SDavid du Colombier csr8w(ctlr, Miicr, cmd);
97672cfc098SDavid du Colombier
977*5b797632SDavid du Colombier for(timeo = 0; timeo < Maxus; timeo++){
97872cfc098SDavid du Colombier if(!(csr8r(ctlr, Miicr) & cmd))
97972cfc098SDavid du Colombier break;
98072cfc098SDavid du Colombier microdelay(1);
98172cfc098SDavid du Colombier }
982*5b797632SDavid du Colombier if(timeo >= Maxus)
98372cfc098SDavid du Colombier return -1;
98472cfc098SDavid du Colombier
98572cfc098SDavid du Colombier if(cmd == Wcmd)
98672cfc098SDavid du Colombier return 0;
98772cfc098SDavid du Colombier return csr16r(ctlr, Miidata);
98872cfc098SDavid du Colombier }
98972cfc098SDavid du Colombier
99072cfc098SDavid du Colombier static int
vt6105Mmiimir(Mii * mii,int pa,int ra)99172cfc098SDavid du Colombier vt6105Mmiimir(Mii* mii, int pa, int ra)
99272cfc098SDavid du Colombier {
99372cfc098SDavid du Colombier return vt6105Mmiimicmd(mii, pa, ra, Rcmd, 0);
99472cfc098SDavid du Colombier }
99572cfc098SDavid du Colombier
99672cfc098SDavid du Colombier static int
vt6105Mmiimiw(Mii * mii,int pa,int ra,int data)99772cfc098SDavid du Colombier vt6105Mmiimiw(Mii* mii, int pa, int ra, int data)
99872cfc098SDavid du Colombier {
99972cfc098SDavid du Colombier return vt6105Mmiimicmd(mii, pa, ra, Wcmd, data);
100072cfc098SDavid du Colombier }
100172cfc098SDavid du Colombier
100272cfc098SDavid du Colombier static int
vt6105Mdetach(Ctlr * ctlr)100372cfc098SDavid du Colombier vt6105Mdetach(Ctlr* ctlr)
100472cfc098SDavid du Colombier {
100572cfc098SDavid du Colombier int revid, timeo;
100672cfc098SDavid du Colombier
100772cfc098SDavid du Colombier /*
100872cfc098SDavid du Colombier * Reset power management registers.
100972cfc098SDavid du Colombier */
101072cfc098SDavid du Colombier revid = pcicfgr8(ctlr->pcidev, PciRID);
101172cfc098SDavid du Colombier if(revid >= 0x40){
101272cfc098SDavid du Colombier /* Set power state D0. */
101372cfc098SDavid du Colombier csr8w(ctlr, Stickhw, csr8r(ctlr, Stickhw) & 0xFC);
101472cfc098SDavid du Colombier
101572cfc098SDavid du Colombier /* Disable force PME-enable. */
101672cfc098SDavid du Colombier csr8w(ctlr, Wolcgclr, 0x80);
101772cfc098SDavid du Colombier
101872cfc098SDavid du Colombier /* Clear WOL config and status bits. */
101972cfc098SDavid du Colombier csr8w(ctlr, Wolcrclr, 0xFF);
102072cfc098SDavid du Colombier csr8w(ctlr, Pwrcsrclr, 0xFF);
102172cfc098SDavid du Colombier }
102272cfc098SDavid du Colombier
102372cfc098SDavid du Colombier /*
102472cfc098SDavid du Colombier * Soft reset the controller.
102572cfc098SDavid du Colombier */
102672cfc098SDavid du Colombier csr16w(ctlr, Cr, Stop);
102772cfc098SDavid du Colombier csr16w(ctlr, Cr, Stop|Sfrst);
1028*5b797632SDavid du Colombier for(timeo = 0; timeo < Maxus; timeo++){
102972cfc098SDavid du Colombier if(!(csr16r(ctlr, Cr) & Sfrst))
103072cfc098SDavid du Colombier break;
103172cfc098SDavid du Colombier microdelay(1);
103272cfc098SDavid du Colombier }
1033*5b797632SDavid du Colombier if(timeo >= Maxus)
103472cfc098SDavid du Colombier return -1;
103572cfc098SDavid du Colombier
103672cfc098SDavid du Colombier return 0;
103772cfc098SDavid du Colombier }
103872cfc098SDavid du Colombier
10390a2a9dafSDavid du Colombier static void
vt6105Mshutdown(Ether * ether)10400a2a9dafSDavid du Colombier vt6105Mshutdown(Ether *ether)
10410a2a9dafSDavid du Colombier {
10420a2a9dafSDavid du Colombier Ctlr *ctlr = ether->ctlr;
10430a2a9dafSDavid du Colombier
10440a2a9dafSDavid du Colombier vt6105Mdetach(ctlr);
10450a2a9dafSDavid du Colombier }
10460a2a9dafSDavid du Colombier
104772cfc098SDavid du Colombier static int
vt6105Mreset(Ctlr * ctlr)104872cfc098SDavid du Colombier vt6105Mreset(Ctlr* ctlr)
104972cfc098SDavid du Colombier {
105072cfc098SDavid du Colombier MiiPhy *phy;
105172cfc098SDavid du Colombier int i, r, timeo;
105272cfc098SDavid du Colombier
105372cfc098SDavid du Colombier if(vt6105Mdetach(ctlr) < 0)
105472cfc098SDavid du Colombier return -1;
105572cfc098SDavid du Colombier
105672cfc098SDavid du Colombier /*
105772cfc098SDavid du Colombier * Load the MAC address into the PAR[01]
105872cfc098SDavid du Colombier * registers.
105972cfc098SDavid du Colombier */
106072cfc098SDavid du Colombier r = csr8r(ctlr, Eecsr);
106172cfc098SDavid du Colombier csr8w(ctlr, Eecsr, Autold|r);
1062*5b797632SDavid du Colombier for(timeo = 0; timeo < Maxus; timeo++){
106372cfc098SDavid du Colombier if(!(csr8r(ctlr, Cr) & Autold))
106472cfc098SDavid du Colombier break;
106572cfc098SDavid du Colombier microdelay(1);
106672cfc098SDavid du Colombier }
1067*5b797632SDavid du Colombier if(timeo >= Maxus)
106872cfc098SDavid du Colombier return -1;
106972cfc098SDavid du Colombier
107072cfc098SDavid du Colombier for(i = 0; i < Eaddrlen; i++)
107172cfc098SDavid du Colombier ctlr->par[i] = csr8r(ctlr, Par0+i);
107272cfc098SDavid du Colombier
107372cfc098SDavid du Colombier /*
107472cfc098SDavid du Colombier * Configure DMA and Rx/Tx thresholds.
107572cfc098SDavid du Colombier * If the Rx/Tx threshold bits in Bcr[01] are 0 then
107672cfc098SDavid du Colombier * the thresholds are determined by Rcr/Tcr.
107772cfc098SDavid du Colombier */
107872cfc098SDavid du Colombier r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK);
107972cfc098SDavid du Colombier csr8w(ctlr, Bcr0, r|Crft128|DmaSAF);
108072cfc098SDavid du Colombier r = csr8r(ctlr, Bcr1) & ~CtftMASK;
108172cfc098SDavid du Colombier csr8w(ctlr, Bcr1, r|ctlr->tft);
108272cfc098SDavid du Colombier
108372cfc098SDavid du Colombier r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep);
108472cfc098SDavid du Colombier csr8w(ctlr, Rcr, r|Ab|Am);
108572cfc098SDavid du Colombier csr32w(ctlr, Mcfilt0, ~0UL); /* accept all multicast */
108672cfc098SDavid du Colombier csr32w(ctlr, Mcfilt1, ~0UL);
108772cfc098SDavid du Colombier
108872cfc098SDavid du Colombier r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0);
108972cfc098SDavid du Colombier csr8w(ctlr, Tcr, r);
109072cfc098SDavid du Colombier
109172cfc098SDavid du Colombier /*
109272cfc098SDavid du Colombier * Link management.
109372cfc098SDavid du Colombier */
109472cfc098SDavid du Colombier if((ctlr->mii = malloc(sizeof(Mii))) == nil)
109572cfc098SDavid du Colombier return -1;
109672cfc098SDavid du Colombier ctlr->mii->mir = vt6105Mmiimir;
109772cfc098SDavid du Colombier ctlr->mii->miw = vt6105Mmiimiw;
109872cfc098SDavid du Colombier ctlr->mii->ctlr = ctlr;
109972cfc098SDavid du Colombier
110072cfc098SDavid du Colombier if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
110172cfc098SDavid du Colombier free(ctlr->mii);
110272cfc098SDavid du Colombier ctlr->mii = nil;
110372cfc098SDavid du Colombier return -1;
110472cfc098SDavid du Colombier }
110572cfc098SDavid du Colombier // print("oui %X phyno %d\n", phy->oui, phy->phyno);
110672cfc098SDavid du Colombier USED(phy);
110772cfc098SDavid du Colombier
110872cfc098SDavid du Colombier if(miistatus(ctlr->mii) < 0){
110972cfc098SDavid du Colombier // miireset(ctlr->mii);
111072cfc098SDavid du Colombier miiane(ctlr->mii, ~0, ~0, ~0);
111172cfc098SDavid du Colombier }
111272cfc098SDavid du Colombier
111372cfc098SDavid du Colombier return 0;
111472cfc098SDavid du Colombier }
111572cfc098SDavid du Colombier
111672cfc098SDavid du Colombier static void
vt6105Mpci(void)111772cfc098SDavid du Colombier vt6105Mpci(void)
111872cfc098SDavid du Colombier {
111972cfc098SDavid du Colombier Pcidev *p;
112072cfc098SDavid du Colombier Ctlr *ctlr;
112172cfc098SDavid du Colombier int cls, port;
112272cfc098SDavid du Colombier
112372cfc098SDavid du Colombier p = nil;
112472cfc098SDavid du Colombier while(p = pcimatch(p, 0, 0)){
112572cfc098SDavid du Colombier if(p->ccrb != Pcibcnet || p->ccru != Pciscether)
112672cfc098SDavid du Colombier continue;
112772cfc098SDavid du Colombier
112872cfc098SDavid du Colombier switch((p->did<<16)|p->vid){
112972cfc098SDavid du Colombier default:
113072cfc098SDavid du Colombier continue;
113172cfc098SDavid du Colombier case (0x3053<<16)|0x1106: /* Rhine III-M vt6105M */
113272cfc098SDavid du Colombier break;
113372cfc098SDavid du Colombier }
113472cfc098SDavid du Colombier
113572cfc098SDavid du Colombier port = p->mem[0].bar & ~0x01;
113672cfc098SDavid du Colombier if(ioalloc(port, p->mem[0].size, 0, "vt6105M") < 0){
113772cfc098SDavid du Colombier print("vt6105M: port 0x%uX in use\n", port);
113872cfc098SDavid du Colombier continue;
113972cfc098SDavid du Colombier }
114072cfc098SDavid du Colombier ctlr = malloc(sizeof(Ctlr));
1141aa72973aSDavid du Colombier if(ctlr == nil) {
1142aa72973aSDavid du Colombier iofree(port);
1143aa72973aSDavid du Colombier error(Enomem);
1144aa72973aSDavid du Colombier }
114572cfc098SDavid du Colombier ctlr->port = port;
114672cfc098SDavid du Colombier ctlr->pcidev = p;
114772cfc098SDavid du Colombier ctlr->id = (p->did<<16)|p->vid;
114872cfc098SDavid du Colombier if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF)
114972cfc098SDavid du Colombier cls = 0x10;
115072cfc098SDavid du Colombier ctlr->cls = cls*4;
115172cfc098SDavid du Colombier if(ctlr->cls < sizeof(Ds)){
115272cfc098SDavid du Colombier print("vt6105M: cls %d < sizeof(Ds)\n", ctlr->cls);
115372cfc098SDavid du Colombier iofree(port);
115472cfc098SDavid du Colombier free(ctlr);
115572cfc098SDavid du Colombier continue;
115672cfc098SDavid du Colombier }
115772cfc098SDavid du Colombier ctlr->tft = CtftSAF;
115872cfc098SDavid du Colombier
115972cfc098SDavid du Colombier if(vt6105Mreset(ctlr)){
116072cfc098SDavid du Colombier iofree(port);
116172cfc098SDavid du Colombier free(ctlr);
116272cfc098SDavid du Colombier continue;
116372cfc098SDavid du Colombier }
116472cfc098SDavid du Colombier pcisetbme(p);
116572cfc098SDavid du Colombier
116672cfc098SDavid du Colombier if(vt6105Mctlrhead != nil)
116772cfc098SDavid du Colombier vt6105Mctlrtail->next = ctlr;
116872cfc098SDavid du Colombier else
116972cfc098SDavid du Colombier vt6105Mctlrhead = ctlr;
117072cfc098SDavid du Colombier vt6105Mctlrtail = ctlr;
117172cfc098SDavid du Colombier }
117272cfc098SDavid du Colombier }
117372cfc098SDavid du Colombier
117472cfc098SDavid du Colombier static int
vt6105Mpnp(Ether * edev)117572cfc098SDavid du Colombier vt6105Mpnp(Ether* edev)
117672cfc098SDavid du Colombier {
117772cfc098SDavid du Colombier Ctlr *ctlr;
117872cfc098SDavid du Colombier
117972cfc098SDavid du Colombier if(vt6105Mctlrhead == nil)
118072cfc098SDavid du Colombier vt6105Mpci();
118172cfc098SDavid du Colombier
118272cfc098SDavid du Colombier /*
118372cfc098SDavid du Colombier * Any adapter matches if no edev->port is supplied,
118472cfc098SDavid du Colombier * otherwise the ports must match.
118572cfc098SDavid du Colombier */
118672cfc098SDavid du Colombier for(ctlr = vt6105Mctlrhead; ctlr != nil; ctlr = ctlr->next){
118772cfc098SDavid du Colombier if(ctlr->active)
118872cfc098SDavid du Colombier continue;
118972cfc098SDavid du Colombier if(edev->port == 0 || edev->port == ctlr->port){
119072cfc098SDavid du Colombier ctlr->active = 1;
119172cfc098SDavid du Colombier break;
119272cfc098SDavid du Colombier }
119372cfc098SDavid du Colombier }
119472cfc098SDavid du Colombier if(ctlr == nil)
119572cfc098SDavid du Colombier return -1;
119672cfc098SDavid du Colombier
119772cfc098SDavid du Colombier edev->ctlr = ctlr;
119872cfc098SDavid du Colombier edev->port = ctlr->port;
119972cfc098SDavid du Colombier edev->irq = ctlr->pcidev->intl;
120072cfc098SDavid du Colombier edev->tbdf = ctlr->pcidev->tbdf;
120172cfc098SDavid du Colombier /*
120272cfc098SDavid du Colombier * Set to 1000Mb/s to fool the bsz calculation. We need
120372cfc098SDavid du Colombier * something better, though.
120472cfc098SDavid du Colombier */
120572cfc098SDavid du Colombier edev->mbps = 1000;
120672cfc098SDavid du Colombier memmove(edev->ea, ctlr->par, Eaddrlen);
120772cfc098SDavid du Colombier
120872cfc098SDavid du Colombier /*
120972cfc098SDavid du Colombier * Linkage to the generic ethernet driver.
121072cfc098SDavid du Colombier */
121172cfc098SDavid du Colombier edev->attach = vt6105Mattach;
121272cfc098SDavid du Colombier edev->transmit = vt6105Mtransmit;
121372cfc098SDavid du Colombier edev->interrupt = vt6105Minterrupt;
121472cfc098SDavid du Colombier edev->ifstat = vt6105Mifstat;
12150a2a9dafSDavid du Colombier edev->shutdown = vt6105Mshutdown;
121672cfc098SDavid du Colombier edev->ctl = nil;
121772cfc098SDavid du Colombier
121872cfc098SDavid du Colombier edev->arg = edev;
121972cfc098SDavid du Colombier edev->promiscuous = vt6105Mpromiscuous;
122072cfc098SDavid du Colombier edev->multicast = vt6105Mmulticast;
122172cfc098SDavid du Colombier
122272cfc098SDavid du Colombier edev->maxmtu = ETHERMAXTU+Bslop;
122372cfc098SDavid du Colombier
122472cfc098SDavid du Colombier return 0;
122572cfc098SDavid du Colombier }
122672cfc098SDavid du Colombier
122772cfc098SDavid du Colombier void
ethervt6105mlink(void)122872cfc098SDavid du Colombier ethervt6105mlink(void)
122972cfc098SDavid du Colombier {
123072cfc098SDavid du Colombier addethercard("vt6105M", vt6105Mpnp);
123172cfc098SDavid du Colombier }
1232