17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * Digital Semiconductor DECchip 2114x PCI Fast Ethernet LAN Controller.
37dd7cddfSDavid du Colombier * To do:
47dd7cddfSDavid du Colombier * thresholds;
57dd7cddfSDavid du Colombier * ring sizing;
67dd7cddfSDavid du Colombier * handle more error conditions;
77dd7cddfSDavid du Colombier * tidy setup packet mess;
87dd7cddfSDavid du Colombier * push initialisation back to attach;
97dd7cddfSDavid du Colombier * full SROM decoding.
107dd7cddfSDavid du Colombier */
117dd7cddfSDavid du Colombier #include "u.h"
127dd7cddfSDavid du Colombier #include "../port/lib.h"
137dd7cddfSDavid du Colombier #include "mem.h"
147dd7cddfSDavid du Colombier #include "dat.h"
157dd7cddfSDavid du Colombier #include "fns.h"
167dd7cddfSDavid du Colombier #include "io.h"
177dd7cddfSDavid du Colombier #include "../port/error.h"
187dd7cddfSDavid du Colombier #include "../port/netif.h"
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier #include "etherif.h"
217dd7cddfSDavid du Colombier
2259cc4ca5SDavid du Colombier #define DEBUG (0)
237dd7cddfSDavid du Colombier #define debug if(DEBUG)print
247dd7cddfSDavid du Colombier
257dd7cddfSDavid du Colombier enum {
267dd7cddfSDavid du Colombier Nrde = 64,
277dd7cddfSDavid du Colombier Ntde = 64,
287dd7cddfSDavid du Colombier };
297dd7cddfSDavid du Colombier
3059cc4ca5SDavid du Colombier #define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)
3159cc4ca5SDavid du Colombier
327dd7cddfSDavid du Colombier enum { /* CRS0 - Bus Mode */
337dd7cddfSDavid du Colombier Swr = 0x00000001, /* Software Reset */
347dd7cddfSDavid du Colombier Bar = 0x00000002, /* Bus Arbitration */
357dd7cddfSDavid du Colombier Dsl = 0x0000007C, /* Descriptor Skip Length (field) */
367dd7cddfSDavid du Colombier Ble = 0x00000080, /* Big/Little Endian */
377dd7cddfSDavid du Colombier Pbl = 0x00003F00, /* Programmable Burst Length (field) */
387dd7cddfSDavid du Colombier Cal = 0x0000C000, /* Cache Alignment (field) */
397dd7cddfSDavid du Colombier Cal8 = 0x00004000, /* 8 longword boundary alignment */
407dd7cddfSDavid du Colombier Cal16 = 0x00008000, /* 16 longword boundary alignment */
417dd7cddfSDavid du Colombier Cal32 = 0x0000C000, /* 32 longword boundary alignment */
427dd7cddfSDavid du Colombier Tap = 0x000E0000, /* Transmit Automatic Polling (field) */
437dd7cddfSDavid du Colombier Dbo = 0x00100000, /* Descriptor Byte Ordering Mode */
447dd7cddfSDavid du Colombier Rml = 0x00200000, /* Read Multiple */
457dd7cddfSDavid du Colombier };
467dd7cddfSDavid du Colombier
477dd7cddfSDavid du Colombier enum { /* CSR[57] - Status and Interrupt Enable */
487dd7cddfSDavid du Colombier Ti = 0x00000001, /* Transmit Interrupt */
497dd7cddfSDavid du Colombier Tps = 0x00000002, /* Transmit Process Stopped */
507dd7cddfSDavid du Colombier Tu = 0x00000004, /* Transmit buffer Unavailable */
517dd7cddfSDavid du Colombier Tjt = 0x00000008, /* Transmit Jabber Timeout */
527dd7cddfSDavid du Colombier Unf = 0x00000020, /* transmit UNderFlow */
537dd7cddfSDavid du Colombier Ri = 0x00000040, /* Receive Interrupt */
547dd7cddfSDavid du Colombier Ru = 0x00000080, /* Receive buffer Unavailable */
557dd7cddfSDavid du Colombier Rps = 0x00000100, /* Receive Process Stopped */
567dd7cddfSDavid du Colombier Rwt = 0x00000200, /* Receive Watchdog Timeout */
577dd7cddfSDavid du Colombier Eti = 0x00000400, /* Early Transmit Interrupt */
587dd7cddfSDavid du Colombier Gte = 0x00000800, /* General purpose Timer Expired */
597dd7cddfSDavid du Colombier Fbe = 0x00002000, /* Fatal Bit Error */
607dd7cddfSDavid du Colombier Ais = 0x00008000, /* Abnormal Interrupt Summary */
617dd7cddfSDavid du Colombier Nis = 0x00010000, /* Normal Interrupt Summary */
627dd7cddfSDavid du Colombier Rs = 0x000E0000, /* Receive process State (field) */
637dd7cddfSDavid du Colombier Ts = 0x00700000, /* Transmit process State (field) */
647dd7cddfSDavid du Colombier Eb = 0x03800000, /* Error bits */
657dd7cddfSDavid du Colombier };
667dd7cddfSDavid du Colombier
677dd7cddfSDavid du Colombier enum { /* CSR6 - Operating Mode */
687dd7cddfSDavid du Colombier Hp = 0x00000001, /* Hash/Perfect receive filtering mode */
697dd7cddfSDavid du Colombier Sr = 0x00000002, /* Start/stop Receive */
707dd7cddfSDavid du Colombier Ho = 0x00000004, /* Hash-Only filtering mode */
717dd7cddfSDavid du Colombier Pb = 0x00000008, /* Pass Bad frames */
727dd7cddfSDavid du Colombier If = 0x00000010, /* Inverse Filtering */
737dd7cddfSDavid du Colombier Sb = 0x00000020, /* Start/stop Backoff counter */
747dd7cddfSDavid du Colombier Pr = 0x00000040, /* Promiscuous Mode */
757dd7cddfSDavid du Colombier Pm = 0x00000080, /* Pass all Multicast */
767dd7cddfSDavid du Colombier Fd = 0x00000200, /* Full Duplex mode */
777dd7cddfSDavid du Colombier Om = 0x00000C00, /* Operating Mode (field) */
787dd7cddfSDavid du Colombier Fc = 0x00001000, /* Force Collision */
797dd7cddfSDavid du Colombier St = 0x00002000, /* Start/stop Transmission Command */
807dd7cddfSDavid du Colombier Tr = 0x0000C000, /* ThReshold control bits (field) */
817dd7cddfSDavid du Colombier Tr128 = 0x00000000,
827dd7cddfSDavid du Colombier Tr256 = 0x00004000,
837dd7cddfSDavid du Colombier Tr512 = 0x00008000,
847dd7cddfSDavid du Colombier Tr1024 = 0x0000C000,
857dd7cddfSDavid du Colombier Ca = 0x00020000, /* CApture effect enable */
867dd7cddfSDavid du Colombier Ps = 0x00040000, /* Port Select */
877dd7cddfSDavid du Colombier Hbd = 0x00080000, /* HeartBeat Disable */
887dd7cddfSDavid du Colombier Imm = 0x00100000, /* IMMediate mode */
897dd7cddfSDavid du Colombier Sf = 0x00200000, /* Store and Forward */
907dd7cddfSDavid du Colombier Ttm = 0x00400000, /* Transmit Threshold Mode */
917dd7cddfSDavid du Colombier Pcs = 0x00800000, /* PCS function */
927dd7cddfSDavid du Colombier Scr = 0x01000000, /* SCRambler mode */
937dd7cddfSDavid du Colombier Mbo = 0x02000000, /* Must Be One */
947dd7cddfSDavid du Colombier Ra = 0x40000000, /* Receive All */
957dd7cddfSDavid du Colombier Sc = 0x80000000, /* Special Capture effect enable */
967dd7cddfSDavid du Colombier
977dd7cddfSDavid du Colombier TrMODE = Tr512, /* default transmission threshold */
987dd7cddfSDavid du Colombier };
997dd7cddfSDavid du Colombier
1007dd7cddfSDavid du Colombier enum { /* CSR9 - ROM and MII Management */
1017dd7cddfSDavid du Colombier Scs = 0x00000001, /* serial ROM chip select */
1027dd7cddfSDavid du Colombier Sclk = 0x00000002, /* serial ROM clock */
1037dd7cddfSDavid du Colombier Sdi = 0x00000004, /* serial ROM data in */
1047dd7cddfSDavid du Colombier Sdo = 0x00000008, /* serial ROM data out */
1057dd7cddfSDavid du Colombier Ss = 0x00000800, /* serial ROM select */
1067dd7cddfSDavid du Colombier Wr = 0x00002000, /* write */
1077dd7cddfSDavid du Colombier Rd = 0x00004000, /* read */
1087dd7cddfSDavid du Colombier
1097dd7cddfSDavid du Colombier Mdc = 0x00010000, /* MII management clock */
1107dd7cddfSDavid du Colombier Mdo = 0x00020000, /* MII management write data */
1117dd7cddfSDavid du Colombier Mii = 0x00040000, /* MII management operation mode (W) */
1127dd7cddfSDavid du Colombier Mdi = 0x00080000, /* MII management data in */
1137dd7cddfSDavid du Colombier };
1147dd7cddfSDavid du Colombier
1157dd7cddfSDavid du Colombier enum { /* CSR12 - General-Purpose Port */
1167dd7cddfSDavid du Colombier Gpc = 0x00000100, /* General Purpose Control */
1177dd7cddfSDavid du Colombier };
1187dd7cddfSDavid du Colombier
1197dd7cddfSDavid du Colombier typedef struct Des {
1207dd7cddfSDavid du Colombier int status;
1217dd7cddfSDavid du Colombier int control;
1227dd7cddfSDavid du Colombier ulong addr;
1237dd7cddfSDavid du Colombier Block* bp;
1247dd7cddfSDavid du Colombier } Des;
1257dd7cddfSDavid du Colombier
1267dd7cddfSDavid du Colombier enum { /* status */
1277dd7cddfSDavid du Colombier Of = 0x00000001, /* Rx: OverFlow */
1287dd7cddfSDavid du Colombier Ce = 0x00000002, /* Rx: CRC Error */
1297dd7cddfSDavid du Colombier Db = 0x00000004, /* Rx: Dribbling Bit */
1307dd7cddfSDavid du Colombier Re = 0x00000008, /* Rx: Report on MII Error */
1317dd7cddfSDavid du Colombier Rw = 0x00000010, /* Rx: Receive Watchdog */
1327dd7cddfSDavid du Colombier Ft = 0x00000020, /* Rx: Frame Type */
1337dd7cddfSDavid du Colombier Cs = 0x00000040, /* Rx: Collision Seen */
1347dd7cddfSDavid du Colombier Tl = 0x00000080, /* Rx: Frame too Long */
1357dd7cddfSDavid du Colombier Ls = 0x00000100, /* Rx: Last deScriptor */
1367dd7cddfSDavid du Colombier Fs = 0x00000200, /* Rx: First deScriptor */
1377dd7cddfSDavid du Colombier Mf = 0x00000400, /* Rx: Multicast Frame */
1387dd7cddfSDavid du Colombier Rf = 0x00000800, /* Rx: Runt Frame */
1397dd7cddfSDavid du Colombier Dt = 0x00003000, /* Rx: Data Type (field) */
1407dd7cddfSDavid du Colombier De = 0x00004000, /* Rx: Descriptor Error */
1417dd7cddfSDavid du Colombier Fl = 0x3FFF0000, /* Rx: Frame Length (field) */
1427dd7cddfSDavid du Colombier Ff = 0x40000000, /* Rx: Filtering Fail */
1437dd7cddfSDavid du Colombier
1447dd7cddfSDavid du Colombier Def = 0x00000001, /* Tx: DEFerred */
1457dd7cddfSDavid du Colombier Uf = 0x00000002, /* Tx: UnderFlow error */
1467dd7cddfSDavid du Colombier Lf = 0x00000004, /* Tx: Link Fail report */
1477dd7cddfSDavid du Colombier Cc = 0x00000078, /* Tx: Collision Count (field) */
1487dd7cddfSDavid du Colombier Hf = 0x00000080, /* Tx: Heartbeat Fail */
1497dd7cddfSDavid du Colombier Ec = 0x00000100, /* Tx: Excessive Collisions */
1507dd7cddfSDavid du Colombier Lc = 0x00000200, /* Tx: Late Collision */
1517dd7cddfSDavid du Colombier Nc = 0x00000400, /* Tx: No Carrier */
1527dd7cddfSDavid du Colombier Lo = 0x00000800, /* Tx: LOss of carrier */
1537dd7cddfSDavid du Colombier To = 0x00004000, /* Tx: Transmission jabber timeOut */
1547dd7cddfSDavid du Colombier
1557dd7cddfSDavid du Colombier Es = 0x00008000, /* [RT]x: Error Summary */
1567dd7cddfSDavid du Colombier Own = 0x80000000, /* [RT]x: OWN bit */
1577dd7cddfSDavid du Colombier };
1587dd7cddfSDavid du Colombier
1597dd7cddfSDavid du Colombier enum { /* control */
1607dd7cddfSDavid du Colombier Bs1 = 0x000007FF, /* [RT]x: Buffer 1 Size */
1617dd7cddfSDavid du Colombier Bs2 = 0x003FF800, /* [RT]x: Buffer 2 Size */
1627dd7cddfSDavid du Colombier
1637dd7cddfSDavid du Colombier Ch = 0x01000000, /* [RT]x: second address CHained */
1647dd7cddfSDavid du Colombier Er = 0x02000000, /* [RT]x: End of Ring */
1657dd7cddfSDavid du Colombier
1667dd7cddfSDavid du Colombier Ft0 = 0x00400000, /* Tx: Filtering Type 0 */
1677dd7cddfSDavid du Colombier Dpd = 0x00800000, /* Tx: Disabled PaDding */
1687dd7cddfSDavid du Colombier Ac = 0x04000000, /* Tx: Add CRC disable */
1697dd7cddfSDavid du Colombier Set = 0x08000000, /* Tx: SETup packet */
1707dd7cddfSDavid du Colombier Ft1 = 0x10000000, /* Tx: Filtering Type 1 */
1717dd7cddfSDavid du Colombier Fseg = 0x20000000, /* Tx: First SEGment */
1727dd7cddfSDavid du Colombier Lseg = 0x40000000, /* Tx: Last SEGment */
1737dd7cddfSDavid du Colombier Ic = 0x80000000, /* Tx: Interrupt on Completion */
1747dd7cddfSDavid du Colombier };
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier enum { /* PHY registers */
1777dd7cddfSDavid du Colombier Bmcr = 0, /* Basic Mode Control */
1787dd7cddfSDavid du Colombier Bmsr = 1, /* Basic Mode Status */
1797dd7cddfSDavid du Colombier Phyidr1 = 2, /* PHY Identifier #1 */
1807dd7cddfSDavid du Colombier Phyidr2 = 3, /* PHY Identifier #2 */
1817dd7cddfSDavid du Colombier Anar = 4, /* Auto-Negotiation Advertisment */
1827dd7cddfSDavid du Colombier Anlpar = 5, /* Auto-Negotiation Link Partner Ability */
1837dd7cddfSDavid du Colombier Aner = 6, /* Auto-Negotiation Expansion */
1847dd7cddfSDavid du Colombier };
1857dd7cddfSDavid du Colombier
18659cc4ca5SDavid du Colombier enum { /* Variants */
18759cc4ca5SDavid du Colombier Tulip0 = (0x0009<<16)|0x1011,
188f43e6a25SDavid du Colombier Tulip1 = (0x0014<<16)|0x1011,
18959cc4ca5SDavid du Colombier Tulip3 = (0x0019<<16)|0x1011,
19059cc4ca5SDavid du Colombier Pnic = (0x0002<<16)|0x11AD,
19159cc4ca5SDavid du Colombier Pnic2 = (0xC115<<16)|0x11AD,
192d9306527SDavid du Colombier CentaurP = (0x0985<<16)|0x1317,
193b4b9fc2fSDavid du Colombier CentaurPcb = (0x1985<<16)|0x1317,
19459cc4ca5SDavid du Colombier };
19559cc4ca5SDavid du Colombier
1967dd7cddfSDavid du Colombier typedef struct Ctlr Ctlr;
1977dd7cddfSDavid du Colombier typedef struct Ctlr {
1987dd7cddfSDavid du Colombier int port;
1997dd7cddfSDavid du Colombier Pcidev* pcidev;
2007dd7cddfSDavid du Colombier Ctlr* next;
2017dd7cddfSDavid du Colombier int active;
20259cc4ca5SDavid du Colombier int id; /* (pcidev->did<<16)|pcidev->vid */
2037dd7cddfSDavid du Colombier
2049a747e4fSDavid du Colombier uchar* srom;
2059a747e4fSDavid du Colombier int sromsz; /* address size in bits */
2067dd7cddfSDavid du Colombier uchar* sromea; /* MAC address */
2077dd7cddfSDavid du Colombier uchar* leaf;
2087dd7cddfSDavid du Colombier int sct; /* selected connection type */
2097dd7cddfSDavid du Colombier int k; /* info block count */
2107dd7cddfSDavid du Colombier uchar* infoblock[16];
2117dd7cddfSDavid du Colombier int sctk; /* sct block index */
2127dd7cddfSDavid du Colombier int curk; /* current block index */
2137dd7cddfSDavid du Colombier uchar* type5block;
2147dd7cddfSDavid du Colombier
2157dd7cddfSDavid du Colombier int phy[32]; /* logical to physical map */
2167dd7cddfSDavid du Colombier int phyreset; /* reset bitmap */
2177dd7cddfSDavid du Colombier int curphyad;
2187dd7cddfSDavid du Colombier int fdx;
2197dd7cddfSDavid du Colombier int ttm;
2207dd7cddfSDavid du Colombier
2217dd7cddfSDavid du Colombier uchar fd; /* option */
2227dd7cddfSDavid du Colombier int medium; /* option */
2237dd7cddfSDavid du Colombier
2247dd7cddfSDavid du Colombier int csr6; /* CSR6 - operating mode */
2257dd7cddfSDavid du Colombier int mask; /* CSR[57] - interrupt mask */
2267dd7cddfSDavid du Colombier int mbps;
2277dd7cddfSDavid du Colombier
2287dd7cddfSDavid du Colombier Lock lock;
2297dd7cddfSDavid du Colombier
2307dd7cddfSDavid du Colombier Des* rdr; /* receive descriptor ring */
2317dd7cddfSDavid du Colombier int nrdr; /* size of rdr */
2327dd7cddfSDavid du Colombier int rdrx; /* index into rdr */
2337dd7cddfSDavid du Colombier
2347dd7cddfSDavid du Colombier Lock tlock;
2357dd7cddfSDavid du Colombier Des* tdr; /* transmit descriptor ring */
2367dd7cddfSDavid du Colombier int ntdr; /* size of tdr */
2377dd7cddfSDavid du Colombier int tdrh; /* host index into tdr */
2387dd7cddfSDavid du Colombier int tdri; /* interface index into tdr */
2397dd7cddfSDavid du Colombier int ntq; /* descriptors active */
2407dd7cddfSDavid du Colombier int ntqmax;
2417dd7cddfSDavid du Colombier Block* setupbp;
2427dd7cddfSDavid du Colombier
2437dd7cddfSDavid du Colombier ulong of; /* receive statistics */
2447dd7cddfSDavid du Colombier ulong ce;
2457dd7cddfSDavid du Colombier ulong cs;
2467dd7cddfSDavid du Colombier ulong tl;
2477dd7cddfSDavid du Colombier ulong rf;
2487dd7cddfSDavid du Colombier ulong de;
2497dd7cddfSDavid du Colombier
2507dd7cddfSDavid du Colombier ulong ru;
2517dd7cddfSDavid du Colombier ulong rps;
2527dd7cddfSDavid du Colombier ulong rwt;
2537dd7cddfSDavid du Colombier
2547dd7cddfSDavid du Colombier ulong uf; /* transmit statistics */
2557dd7cddfSDavid du Colombier ulong ec;
2567dd7cddfSDavid du Colombier ulong lc;
2577dd7cddfSDavid du Colombier ulong nc;
2587dd7cddfSDavid du Colombier ulong lo;
2597dd7cddfSDavid du Colombier ulong to;
2607dd7cddfSDavid du Colombier
2617dd7cddfSDavid du Colombier ulong tps;
2627dd7cddfSDavid du Colombier ulong tu;
2637dd7cddfSDavid du Colombier ulong tjt;
2647dd7cddfSDavid du Colombier ulong unf;
2657dd7cddfSDavid du Colombier } Ctlr;
2667dd7cddfSDavid du Colombier
2677dd7cddfSDavid du Colombier static Ctlr* ctlrhead;
2687dd7cddfSDavid du Colombier static Ctlr* ctlrtail;
2697dd7cddfSDavid du Colombier
2707dd7cddfSDavid du Colombier #define csr32r(c, r) (inl((c)->port+((r)*8)))
2717dd7cddfSDavid du Colombier #define csr32w(c, r, l) (outl((c)->port+((r)*8), (ulong)(l)))
2727dd7cddfSDavid du Colombier
2737dd7cddfSDavid du Colombier static void
promiscuous(void * arg,int on)2747dd7cddfSDavid du Colombier promiscuous(void* arg, int on)
2757dd7cddfSDavid du Colombier {
2767dd7cddfSDavid du Colombier Ctlr *ctlr;
2777dd7cddfSDavid du Colombier
2787dd7cddfSDavid du Colombier ctlr = ((Ether*)arg)->ctlr;
2797dd7cddfSDavid du Colombier ilock(&ctlr->lock);
2807dd7cddfSDavid du Colombier if(on)
2817dd7cddfSDavid du Colombier ctlr->csr6 |= Pr;
2827dd7cddfSDavid du Colombier else
2837dd7cddfSDavid du Colombier ctlr->csr6 &= ~Pr;
2847dd7cddfSDavid du Colombier csr32w(ctlr, 6, ctlr->csr6);
2857dd7cddfSDavid du Colombier iunlock(&ctlr->lock);
2867dd7cddfSDavid du Colombier }
2877dd7cddfSDavid du Colombier
2880809e9a7SDavid du Colombier /* multicast already on, don't need to do anything */
2890809e9a7SDavid du Colombier static void
multicast(void *,uchar *,int)2900809e9a7SDavid du Colombier multicast(void*, uchar*, int)
2910809e9a7SDavid du Colombier {
2920809e9a7SDavid du Colombier }
2930809e9a7SDavid du Colombier
2947dd7cddfSDavid du Colombier static void
attach(Ether * ether)2957dd7cddfSDavid du Colombier attach(Ether* ether)
2967dd7cddfSDavid du Colombier {
2977dd7cddfSDavid du Colombier Ctlr *ctlr;
2987dd7cddfSDavid du Colombier
2997dd7cddfSDavid du Colombier ctlr = ether->ctlr;
3007dd7cddfSDavid du Colombier ilock(&ctlr->lock);
3017dd7cddfSDavid du Colombier if(!(ctlr->csr6 & Sr)){
3027dd7cddfSDavid du Colombier ctlr->csr6 |= Sr;
3037dd7cddfSDavid du Colombier csr32w(ctlr, 6, ctlr->csr6);
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier iunlock(&ctlr->lock);
3067dd7cddfSDavid du Colombier }
3077dd7cddfSDavid du Colombier
3087dd7cddfSDavid du Colombier static long
ifstat(Ether * ether,void * a,long n,ulong offset)3097dd7cddfSDavid du Colombier ifstat(Ether* ether, void* a, long n, ulong offset)
3107dd7cddfSDavid du Colombier {
3117dd7cddfSDavid du Colombier Ctlr *ctlr;
3127dd7cddfSDavid du Colombier char *buf, *p;
3137dd7cddfSDavid du Colombier int i, l, len;
3147dd7cddfSDavid du Colombier
3157dd7cddfSDavid du Colombier ctlr = ether->ctlr;
3167dd7cddfSDavid du Colombier
3177dd7cddfSDavid du Colombier ether->crcs = ctlr->ce;
3187dd7cddfSDavid du Colombier ether->frames = ctlr->rf+ctlr->cs;
3197dd7cddfSDavid du Colombier ether->buffs = ctlr->de+ctlr->tl;
3207dd7cddfSDavid du Colombier ether->overflows = ctlr->of;
3217dd7cddfSDavid du Colombier
3227dd7cddfSDavid du Colombier if(n == 0)
3237dd7cddfSDavid du Colombier return 0;
3247dd7cddfSDavid du Colombier
3257dd7cddfSDavid du Colombier p = malloc(READSTR);
326aa72973aSDavid du Colombier if(p == nil)
327aa72973aSDavid du Colombier error(Enomem);
3287dd7cddfSDavid du Colombier l = snprint(p, READSTR, "Overflow: %lud\n", ctlr->of);
3297dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Ru: %lud\n", ctlr->ru);
3307dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Rps: %lud\n", ctlr->rps);
3317dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Rwt: %lud\n", ctlr->rwt);
3327dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Tps: %lud\n", ctlr->tps);
3337dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Tu: %lud\n", ctlr->tu);
3347dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Tjt: %lud\n", ctlr->tjt);
3357dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Unf: %lud\n", ctlr->unf);
3367dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "CRC Error: %lud\n", ctlr->ce);
3377dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Collision Seen: %lud\n", ctlr->cs);
3387dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Frame Too Long: %lud\n", ctlr->tl);
3397dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Runt Frame: %lud\n", ctlr->rf);
3407dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Descriptor Error: %lud\n", ctlr->de);
3417dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Underflow Error: %lud\n", ctlr->uf);
3427dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Excessive Collisions: %lud\n", ctlr->ec);
3437dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Late Collision: %lud\n", ctlr->lc);
3447dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "No Carrier: %lud\n", ctlr->nc);
3457dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Loss of Carrier: %lud\n", ctlr->lo);
3467dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "Transmit Jabber Timeout: %lud\n",
3477dd7cddfSDavid du Colombier ctlr->to);
3487dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "csr6: %luX %uX\n", csr32r(ctlr, 6),
3497dd7cddfSDavid du Colombier ctlr->csr6);
3507dd7cddfSDavid du Colombier snprint(p+l, READSTR-l, "ntqmax: %d\n", ctlr->ntqmax);
3517dd7cddfSDavid du Colombier ctlr->ntqmax = 0;
3527dd7cddfSDavid du Colombier buf = a;
3537dd7cddfSDavid du Colombier len = readstr(offset, buf, n, p);
3547dd7cddfSDavid du Colombier if(offset > l)
3557dd7cddfSDavid du Colombier offset -= l;
3567dd7cddfSDavid du Colombier else
3577dd7cddfSDavid du Colombier offset = 0;
3587dd7cddfSDavid du Colombier buf += len;
3597dd7cddfSDavid du Colombier n -= len;
3607dd7cddfSDavid du Colombier
3617dd7cddfSDavid du Colombier l = snprint(p, READSTR, "srom:");
3629a747e4fSDavid du Colombier for(i = 0; i < (1<<(ctlr->sromsz)*sizeof(ushort)); i++){
3637dd7cddfSDavid du Colombier if(i && ((i & 0x0F) == 0))
3647dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, "\n ");
3657dd7cddfSDavid du Colombier l += snprint(p+l, READSTR-l, " %2.2uX", ctlr->srom[i]);
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier snprint(p+l, READSTR-l, "\n");
3697dd7cddfSDavid du Colombier len += readstr(offset, buf, n, p);
3707dd7cddfSDavid du Colombier free(p);
3717dd7cddfSDavid du Colombier
3727dd7cddfSDavid du Colombier return len;
3737dd7cddfSDavid du Colombier }
3747dd7cddfSDavid du Colombier
3757dd7cddfSDavid du Colombier static void
txstart(Ether * ether)3767dd7cddfSDavid du Colombier txstart(Ether* ether)
3777dd7cddfSDavid du Colombier {
3787dd7cddfSDavid du Colombier Ctlr *ctlr;
3797dd7cddfSDavid du Colombier Block *bp;
3807dd7cddfSDavid du Colombier Des *des;
3817dd7cddfSDavid du Colombier int control;
3827dd7cddfSDavid du Colombier
3837dd7cddfSDavid du Colombier ctlr = ether->ctlr;
3847dd7cddfSDavid du Colombier while(ctlr->ntq < (ctlr->ntdr-1)){
3857dd7cddfSDavid du Colombier if(ctlr->setupbp){
3867dd7cddfSDavid du Colombier bp = ctlr->setupbp;
3877dd7cddfSDavid du Colombier ctlr->setupbp = 0;
3887dd7cddfSDavid du Colombier control = Ic|Set|BLEN(bp);
3897dd7cddfSDavid du Colombier }
3907dd7cddfSDavid du Colombier else{
3917dd7cddfSDavid du Colombier bp = qget(ether->oq);
3927dd7cddfSDavid du Colombier if(bp == nil)
3937dd7cddfSDavid du Colombier break;
3947dd7cddfSDavid du Colombier control = Ic|Lseg|Fseg|BLEN(bp);
3957dd7cddfSDavid du Colombier }
3967dd7cddfSDavid du Colombier
3977dd7cddfSDavid du Colombier ctlr->tdr[PREV(ctlr->tdrh, ctlr->ntdr)].control &= ~Ic;
3987dd7cddfSDavid du Colombier des = &ctlr->tdr[ctlr->tdrh];
3997dd7cddfSDavid du Colombier des->bp = bp;
4009a747e4fSDavid du Colombier des->addr = PCIWADDR(bp->rp);
4017dd7cddfSDavid du Colombier des->control |= control;
4027dd7cddfSDavid du Colombier ctlr->ntq++;
4037dd7cddfSDavid du Colombier coherence();
4047dd7cddfSDavid du Colombier des->status = Own;
4057dd7cddfSDavid du Colombier csr32w(ctlr, 1, 0);
4067dd7cddfSDavid du Colombier ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr);
4077dd7cddfSDavid du Colombier }
4087dd7cddfSDavid du Colombier
4097dd7cddfSDavid du Colombier if(ctlr->ntq > ctlr->ntqmax)
4107dd7cddfSDavid du Colombier ctlr->ntqmax = ctlr->ntq;
4117dd7cddfSDavid du Colombier }
4127dd7cddfSDavid du Colombier
4137dd7cddfSDavid du Colombier static void
transmit(Ether * ether)4147dd7cddfSDavid du Colombier transmit(Ether* ether)
4157dd7cddfSDavid du Colombier {
4167dd7cddfSDavid du Colombier Ctlr *ctlr;
4177dd7cddfSDavid du Colombier
4187dd7cddfSDavid du Colombier ctlr = ether->ctlr;
4197dd7cddfSDavid du Colombier ilock(&ctlr->tlock);
4207dd7cddfSDavid du Colombier txstart(ether);
4217dd7cddfSDavid du Colombier iunlock(&ctlr->tlock);
4227dd7cddfSDavid du Colombier }
4237dd7cddfSDavid du Colombier
4247dd7cddfSDavid du Colombier static void
interrupt(Ureg *,void * arg)4257dd7cddfSDavid du Colombier interrupt(Ureg*, void* arg)
4267dd7cddfSDavid du Colombier {
4277dd7cddfSDavid du Colombier Ctlr *ctlr;
4287dd7cddfSDavid du Colombier Ether *ether;
4297dd7cddfSDavid du Colombier int len, status;
4307dd7cddfSDavid du Colombier Des *des;
4317dd7cddfSDavid du Colombier Block *bp;
4327dd7cddfSDavid du Colombier
4337dd7cddfSDavid du Colombier ether = arg;
4347dd7cddfSDavid du Colombier ctlr = ether->ctlr;
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier while((status = csr32r(ctlr, 5)) & (Nis|Ais)){
4377dd7cddfSDavid du Colombier /*
4387dd7cddfSDavid du Colombier * Acknowledge the interrupts and mask-out
4397dd7cddfSDavid du Colombier * the ones that are implicitly handled.
4407dd7cddfSDavid du Colombier */
4417dd7cddfSDavid du Colombier csr32w(ctlr, 5, status);
4427dd7cddfSDavid du Colombier status &= (ctlr->mask & ~(Nis|Ti));
4437dd7cddfSDavid du Colombier
4447dd7cddfSDavid du Colombier if(status & Ais){
4457dd7cddfSDavid du Colombier if(status & Tps)
4467dd7cddfSDavid du Colombier ctlr->tps++;
4477dd7cddfSDavid du Colombier if(status & Tu)
4487dd7cddfSDavid du Colombier ctlr->tu++;
4497dd7cddfSDavid du Colombier if(status & Tjt)
4507dd7cddfSDavid du Colombier ctlr->tjt++;
4517dd7cddfSDavid du Colombier if(status & Ru)
4527dd7cddfSDavid du Colombier ctlr->ru++;
4537dd7cddfSDavid du Colombier if(status & Rps)
4547dd7cddfSDavid du Colombier ctlr->rps++;
4557dd7cddfSDavid du Colombier if(status & Rwt)
4567dd7cddfSDavid du Colombier ctlr->rwt++;
4577dd7cddfSDavid du Colombier status &= ~(Ais|Rwt|Rps|Ru|Tjt|Tu|Tps);
4587dd7cddfSDavid du Colombier }
4597dd7cddfSDavid du Colombier
4607dd7cddfSDavid du Colombier /*
4617dd7cddfSDavid du Colombier * Received packets.
4627dd7cddfSDavid du Colombier */
4637dd7cddfSDavid du Colombier if(status & Ri){
4647dd7cddfSDavid du Colombier des = &ctlr->rdr[ctlr->rdrx];
4657dd7cddfSDavid du Colombier while(!(des->status & Own)){
4667dd7cddfSDavid du Colombier if(des->status & Es){
4677dd7cddfSDavid du Colombier if(des->status & Of)
4687dd7cddfSDavid du Colombier ctlr->of++;
4697dd7cddfSDavid du Colombier if(des->status & Ce)
4707dd7cddfSDavid du Colombier ctlr->ce++;
4717dd7cddfSDavid du Colombier if(des->status & Cs)
4727dd7cddfSDavid du Colombier ctlr->cs++;
4737dd7cddfSDavid du Colombier if(des->status & Tl)
4747dd7cddfSDavid du Colombier ctlr->tl++;
4757dd7cddfSDavid du Colombier if(des->status & Rf)
4767dd7cddfSDavid du Colombier ctlr->rf++;
4777dd7cddfSDavid du Colombier if(des->status & De)
4787dd7cddfSDavid du Colombier ctlr->de++;
4797dd7cddfSDavid du Colombier }
48059cc4ca5SDavid du Colombier else if(bp = iallocb(Rbsz)){
4817dd7cddfSDavid du Colombier len = ((des->status & Fl)>>16)-4;
4827dd7cddfSDavid du Colombier des->bp->wp = des->bp->rp+len;
4837dd7cddfSDavid du Colombier etheriq(ether, des->bp, 1);
4847dd7cddfSDavid du Colombier des->bp = bp;
4859a747e4fSDavid du Colombier des->addr = PCIWADDR(bp->rp);
4867dd7cddfSDavid du Colombier }
4877dd7cddfSDavid du Colombier
4887dd7cddfSDavid du Colombier des->control &= Er;
48959cc4ca5SDavid du Colombier des->control |= Rbsz;
4907dd7cddfSDavid du Colombier coherence();
4917dd7cddfSDavid du Colombier des->status = Own;
4927dd7cddfSDavid du Colombier
4937dd7cddfSDavid du Colombier ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr);
4947dd7cddfSDavid du Colombier des = &ctlr->rdr[ctlr->rdrx];
4957dd7cddfSDavid du Colombier }
4967dd7cddfSDavid du Colombier status &= ~Ri;
4977dd7cddfSDavid du Colombier }
4987dd7cddfSDavid du Colombier
4997dd7cddfSDavid du Colombier /*
5007dd7cddfSDavid du Colombier * Check the transmit side:
5017dd7cddfSDavid du Colombier * check for Transmit Underflow and Adjust
5027dd7cddfSDavid du Colombier * the threshold upwards;
5037dd7cddfSDavid du Colombier * free any transmitted buffers and try to
5047dd7cddfSDavid du Colombier * top-up the ring.
5057dd7cddfSDavid du Colombier */
5067dd7cddfSDavid du Colombier if(status & Unf){
5077dd7cddfSDavid du Colombier ctlr->unf++;
5087dd7cddfSDavid du Colombier ilock(&ctlr->lock);
5097dd7cddfSDavid du Colombier csr32w(ctlr, 6, ctlr->csr6 & ~St);
5107dd7cddfSDavid du Colombier switch(ctlr->csr6 & Tr){
5117dd7cddfSDavid du Colombier case Tr128:
5127dd7cddfSDavid du Colombier len = Tr256;
5137dd7cddfSDavid du Colombier break;
5147dd7cddfSDavid du Colombier case Tr256:
5157dd7cddfSDavid du Colombier len = Tr512;
5167dd7cddfSDavid du Colombier break;
5177dd7cddfSDavid du Colombier case Tr512:
5187dd7cddfSDavid du Colombier len = Tr1024;
5197dd7cddfSDavid du Colombier break;
5207dd7cddfSDavid du Colombier default:
5217dd7cddfSDavid du Colombier case Tr1024:
5227dd7cddfSDavid du Colombier len = Sf;
5237dd7cddfSDavid du Colombier break;
5247dd7cddfSDavid du Colombier }
5257dd7cddfSDavid du Colombier ctlr->csr6 = (ctlr->csr6 & ~Tr)|len;
5267dd7cddfSDavid du Colombier csr32w(ctlr, 6, ctlr->csr6);
5277dd7cddfSDavid du Colombier iunlock(&ctlr->lock);
5287dd7cddfSDavid du Colombier csr32w(ctlr, 5, Tps);
5297dd7cddfSDavid du Colombier status &= ~(Unf|Tps);
5307dd7cddfSDavid du Colombier }
5317dd7cddfSDavid du Colombier
5327dd7cddfSDavid du Colombier ilock(&ctlr->tlock);
5337dd7cddfSDavid du Colombier while(ctlr->ntq){
5347dd7cddfSDavid du Colombier des = &ctlr->tdr[ctlr->tdri];
5357dd7cddfSDavid du Colombier if(des->status & Own)
5367dd7cddfSDavid du Colombier break;
5377dd7cddfSDavid du Colombier
5387dd7cddfSDavid du Colombier if(des->status & Es){
5397dd7cddfSDavid du Colombier if(des->status & Uf)
5407dd7cddfSDavid du Colombier ctlr->uf++;
5417dd7cddfSDavid du Colombier if(des->status & Ec)
5427dd7cddfSDavid du Colombier ctlr->ec++;
5437dd7cddfSDavid du Colombier if(des->status & Lc)
5447dd7cddfSDavid du Colombier ctlr->lc++;
5457dd7cddfSDavid du Colombier if(des->status & Nc)
5467dd7cddfSDavid du Colombier ctlr->nc++;
5477dd7cddfSDavid du Colombier if(des->status & Lo)
5487dd7cddfSDavid du Colombier ctlr->lo++;
5497dd7cddfSDavid du Colombier if(des->status & To)
5507dd7cddfSDavid du Colombier ctlr->to++;
5517dd7cddfSDavid du Colombier ether->oerrs++;
5527dd7cddfSDavid du Colombier }
5537dd7cddfSDavid du Colombier
5547dd7cddfSDavid du Colombier freeb(des->bp);
5557dd7cddfSDavid du Colombier des->control &= Er;
5567dd7cddfSDavid du Colombier
5577dd7cddfSDavid du Colombier ctlr->ntq--;
5587dd7cddfSDavid du Colombier ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr);
5597dd7cddfSDavid du Colombier }
5607dd7cddfSDavid du Colombier txstart(ether);
5617dd7cddfSDavid du Colombier iunlock(&ctlr->tlock);
5627dd7cddfSDavid du Colombier
5637dd7cddfSDavid du Colombier /*
5647dd7cddfSDavid du Colombier * Anything left not catered for?
5657dd7cddfSDavid du Colombier */
5667dd7cddfSDavid du Colombier if(status)
5677dd7cddfSDavid du Colombier panic("#l%d: status %8.8uX\n", ether->ctlrno, status);
5687dd7cddfSDavid du Colombier }
5697dd7cddfSDavid du Colombier }
5707dd7cddfSDavid du Colombier
5717dd7cddfSDavid du Colombier static void
ctlrinit(Ether * ether)5727dd7cddfSDavid du Colombier ctlrinit(Ether* ether)
5737dd7cddfSDavid du Colombier {
5747dd7cddfSDavid du Colombier Ctlr *ctlr;
5757dd7cddfSDavid du Colombier Des *des;
5767dd7cddfSDavid du Colombier Block *bp;
5777dd7cddfSDavid du Colombier int i;
5787dd7cddfSDavid du Colombier uchar bi[Eaddrlen*2];
5797dd7cddfSDavid du Colombier
5807dd7cddfSDavid du Colombier ctlr = ether->ctlr;
5817dd7cddfSDavid du Colombier
5827dd7cddfSDavid du Colombier /*
5837dd7cddfSDavid du Colombier * Allocate and initialise the receive ring;
5847dd7cddfSDavid du Colombier * allocate and initialise the transmit ring;
5857dd7cddfSDavid du Colombier * unmask interrupts and start the transmit side;
5867dd7cddfSDavid du Colombier * create and post a setup packet to initialise
5877dd7cddfSDavid du Colombier * the physical ethernet address.
5887dd7cddfSDavid du Colombier */
5899a747e4fSDavid du Colombier ctlr->rdr = xspanalloc(ctlr->nrdr*sizeof(Des), 8*sizeof(ulong), 0);
5907dd7cddfSDavid du Colombier for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){
5919a747e4fSDavid du Colombier des->bp = iallocb(Rbsz);
5929a747e4fSDavid du Colombier if(des->bp == nil)
5939a747e4fSDavid du Colombier panic("can't allocate ethernet receive ring\n");
5947dd7cddfSDavid du Colombier des->status = Own;
59559cc4ca5SDavid du Colombier des->control = Rbsz;
5969a747e4fSDavid du Colombier des->addr = PCIWADDR(des->bp->rp);
5977dd7cddfSDavid du Colombier }
5987dd7cddfSDavid du Colombier ctlr->rdr[ctlr->nrdr-1].control |= Er;
5997dd7cddfSDavid du Colombier ctlr->rdrx = 0;
6009a747e4fSDavid du Colombier csr32w(ctlr, 3, PCIWADDR(ctlr->rdr));
6017dd7cddfSDavid du Colombier
6027dd7cddfSDavid du Colombier ctlr->tdr = xspanalloc(ctlr->ntdr*sizeof(Des), 8*sizeof(ulong), 0);
6037dd7cddfSDavid du Colombier ctlr->tdr[ctlr->ntdr-1].control |= Er;
6047dd7cddfSDavid du Colombier ctlr->tdrh = 0;
6057dd7cddfSDavid du Colombier ctlr->tdri = 0;
6069a747e4fSDavid du Colombier csr32w(ctlr, 4, PCIWADDR(ctlr->tdr));
6077dd7cddfSDavid du Colombier
60859cc4ca5SDavid du Colombier /*
60959cc4ca5SDavid du Colombier * Clear any bits in the Status Register (CSR5) as
61059cc4ca5SDavid du Colombier * the PNIC has a different reset value from a true 2114x.
61159cc4ca5SDavid du Colombier */
6127dd7cddfSDavid du Colombier ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti;
61359cc4ca5SDavid du Colombier csr32w(ctlr, 5, ctlr->mask);
6147dd7cddfSDavid du Colombier csr32w(ctlr, 7, ctlr->mask);
6150809e9a7SDavid du Colombier ctlr->csr6 |= St|Pm;
6167dd7cddfSDavid du Colombier csr32w(ctlr, 6, ctlr->csr6);
6177dd7cddfSDavid du Colombier
6187dd7cddfSDavid du Colombier for(i = 0; i < Eaddrlen/2; i++){
6197dd7cddfSDavid du Colombier bi[i*4] = ether->ea[i*2];
6207dd7cddfSDavid du Colombier bi[i*4+1] = ether->ea[i*2+1];
6217dd7cddfSDavid du Colombier bi[i*4+2] = ether->ea[i*2+1];
6227dd7cddfSDavid du Colombier bi[i*4+3] = ether->ea[i*2];
6237dd7cddfSDavid du Colombier }
6249a747e4fSDavid du Colombier bp = iallocb(Eaddrlen*2*16);
6259a747e4fSDavid du Colombier if(bp == nil)
6269a747e4fSDavid du Colombier panic("can't allocate ethernet setup buffer\n");
6277dd7cddfSDavid du Colombier memset(bp->rp, 0xFF, sizeof(bi));
6287dd7cddfSDavid du Colombier for(i = sizeof(bi); i < sizeof(bi)*16; i += sizeof(bi))
6297dd7cddfSDavid du Colombier memmove(bp->rp+i, bi, sizeof(bi));
6307dd7cddfSDavid du Colombier bp->wp += sizeof(bi)*16;
6317dd7cddfSDavid du Colombier
6327dd7cddfSDavid du Colombier ctlr->setupbp = bp;
633*6520663fSDavid du Colombier ether->oq = qopen(64*1024, Qmsg, 0, 0);
6347dd7cddfSDavid du Colombier transmit(ether);
6357dd7cddfSDavid du Colombier }
6367dd7cddfSDavid du Colombier
6377dd7cddfSDavid du Colombier static void
csr9w(Ctlr * ctlr,int data)6387dd7cddfSDavid du Colombier csr9w(Ctlr* ctlr, int data)
6397dd7cddfSDavid du Colombier {
6407dd7cddfSDavid du Colombier csr32w(ctlr, 9, data);
6417dd7cddfSDavid du Colombier microdelay(1);
6427dd7cddfSDavid du Colombier }
6437dd7cddfSDavid du Colombier
6447dd7cddfSDavid du Colombier static int
miimdi(Ctlr * ctlr,int n)6457dd7cddfSDavid du Colombier miimdi(Ctlr* ctlr, int n)
6467dd7cddfSDavid du Colombier {
6477dd7cddfSDavid du Colombier int data, i;
6487dd7cddfSDavid du Colombier
6497dd7cddfSDavid du Colombier /*
6507dd7cddfSDavid du Colombier * Read n bits from the MII Management Register.
6517dd7cddfSDavid du Colombier */
6527dd7cddfSDavid du Colombier data = 0;
6537dd7cddfSDavid du Colombier for(i = n-1; i >= 0; i--){
6547dd7cddfSDavid du Colombier if(csr32r(ctlr, 9) & Mdi)
6557dd7cddfSDavid du Colombier data |= (1<<i);
6567dd7cddfSDavid du Colombier csr9w(ctlr, Mii|Mdc);
6577dd7cddfSDavid du Colombier csr9w(ctlr, Mii);
6587dd7cddfSDavid du Colombier }
6597dd7cddfSDavid du Colombier csr9w(ctlr, 0);
6607dd7cddfSDavid du Colombier
6617dd7cddfSDavid du Colombier return data;
6627dd7cddfSDavid du Colombier }
6637dd7cddfSDavid du Colombier
6647dd7cddfSDavid du Colombier static void
miimdo(Ctlr * ctlr,int bits,int n)6657dd7cddfSDavid du Colombier miimdo(Ctlr* ctlr, int bits, int n)
6667dd7cddfSDavid du Colombier {
6677dd7cddfSDavid du Colombier int i, mdo;
6687dd7cddfSDavid du Colombier
6697dd7cddfSDavid du Colombier /*
6707dd7cddfSDavid du Colombier * Write n bits to the MII Management Register.
6717dd7cddfSDavid du Colombier */
6727dd7cddfSDavid du Colombier for(i = n-1; i >= 0; i--){
6737dd7cddfSDavid du Colombier if(bits & (1<<i))
6747dd7cddfSDavid du Colombier mdo = Mdo;
6757dd7cddfSDavid du Colombier else
6767dd7cddfSDavid du Colombier mdo = 0;
6777dd7cddfSDavid du Colombier csr9w(ctlr, mdo);
6787dd7cddfSDavid du Colombier csr9w(ctlr, mdo|Mdc);
6797dd7cddfSDavid du Colombier csr9w(ctlr, mdo);
6807dd7cddfSDavid du Colombier }
6817dd7cddfSDavid du Colombier }
6827dd7cddfSDavid du Colombier
6837dd7cddfSDavid du Colombier static int
miir(Ctlr * ctlr,int phyad,int regad)6847dd7cddfSDavid du Colombier miir(Ctlr* ctlr, int phyad, int regad)
6857dd7cddfSDavid du Colombier {
68659cc4ca5SDavid du Colombier int data, i;
68759cc4ca5SDavid du Colombier
68859cc4ca5SDavid du Colombier if(ctlr->id == Pnic){
68959cc4ca5SDavid du Colombier i = 1000;
69059cc4ca5SDavid du Colombier csr32w(ctlr, 20, 0x60020000|(phyad<<23)|(regad<<18));
69159cc4ca5SDavid du Colombier do{
69259cc4ca5SDavid du Colombier microdelay(1);
69359cc4ca5SDavid du Colombier data = csr32r(ctlr, 20);
69459cc4ca5SDavid du Colombier }while((data & 0x80000000) && --i);
69559cc4ca5SDavid du Colombier
69659cc4ca5SDavid du Colombier if(i == 0)
69759cc4ca5SDavid du Colombier return -1;
69859cc4ca5SDavid du Colombier return data & 0xFFFF;
69959cc4ca5SDavid du Colombier }
7007dd7cddfSDavid du Colombier
7017dd7cddfSDavid du Colombier /*
7027dd7cddfSDavid du Colombier * Preamble;
7037dd7cddfSDavid du Colombier * ST+OP+PHYAD+REGAD;
7047dd7cddfSDavid du Colombier * TA + 16 data bits.
7057dd7cddfSDavid du Colombier */
7067dd7cddfSDavid du Colombier miimdo(ctlr, 0xFFFFFFFF, 32);
7077dd7cddfSDavid du Colombier miimdo(ctlr, 0x1800|(phyad<<5)|regad, 14);
7087dd7cddfSDavid du Colombier data = miimdi(ctlr, 18);
7097dd7cddfSDavid du Colombier
7107dd7cddfSDavid du Colombier if(data & 0x10000)
7117dd7cddfSDavid du Colombier return -1;
7127dd7cddfSDavid du Colombier
7137dd7cddfSDavid du Colombier return data & 0xFFFF;
7147dd7cddfSDavid du Colombier }
7157dd7cddfSDavid du Colombier
7167dd7cddfSDavid du Colombier static void
miiw(Ctlr * ctlr,int phyad,int regad,int data)7177dd7cddfSDavid du Colombier miiw(Ctlr* ctlr, int phyad, int regad, int data)
7187dd7cddfSDavid du Colombier {
7197dd7cddfSDavid du Colombier /*
7207dd7cddfSDavid du Colombier * Preamble;
7217dd7cddfSDavid du Colombier * ST+OP+PHYAD+REGAD+TA + 16 data bits;
7227dd7cddfSDavid du Colombier * Z.
7237dd7cddfSDavid du Colombier */
7247dd7cddfSDavid du Colombier miimdo(ctlr, 0xFFFFFFFF, 32);
7257dd7cddfSDavid du Colombier data &= 0xFFFF;
7267dd7cddfSDavid du Colombier data |= (0x05<<(5+5+2+16))|(phyad<<(5+2+16))|(regad<<(2+16))|(0x02<<16);
7277dd7cddfSDavid du Colombier miimdo(ctlr, data, 32);
7287dd7cddfSDavid du Colombier csr9w(ctlr, Mdc);
7297dd7cddfSDavid du Colombier csr9w(ctlr, 0);
7307dd7cddfSDavid du Colombier }
7317dd7cddfSDavid du Colombier
7327dd7cddfSDavid du Colombier static int
sromr(Ctlr * ctlr,int r)7337dd7cddfSDavid du Colombier sromr(Ctlr* ctlr, int r)
7347dd7cddfSDavid du Colombier {
7359a747e4fSDavid du Colombier int i, op, data, size;
7367dd7cddfSDavid du Colombier
73759cc4ca5SDavid du Colombier if(ctlr->id == Pnic){
73859cc4ca5SDavid du Colombier i = 1000;
73959cc4ca5SDavid du Colombier csr32w(ctlr, 19, 0x600|r);
74059cc4ca5SDavid du Colombier do{
74159cc4ca5SDavid du Colombier microdelay(1);
74259cc4ca5SDavid du Colombier data = csr32r(ctlr, 19);
74359cc4ca5SDavid du Colombier }while((data & 0x80000000) && --i);
74459cc4ca5SDavid du Colombier
7459a747e4fSDavid du Colombier if(ctlr->sromsz == 0)
7469a747e4fSDavid du Colombier ctlr->sromsz = 6;
7479a747e4fSDavid du Colombier
74859cc4ca5SDavid du Colombier return csr32r(ctlr, 9) & 0xFFFF;
74959cc4ca5SDavid du Colombier }
75059cc4ca5SDavid du Colombier
7517dd7cddfSDavid du Colombier /*
7527dd7cddfSDavid du Colombier * This sequence for reading a 16-bit register 'r'
753f43e6a25SDavid du Colombier * in the EEPROM is taken (pretty much) straight from Section
7547dd7cddfSDavid du Colombier * 7.4 of the 21140 Hardware Reference Manual.
7557dd7cddfSDavid du Colombier */
7569a747e4fSDavid du Colombier reread:
7577dd7cddfSDavid du Colombier csr9w(ctlr, Rd|Ss);
7587dd7cddfSDavid du Colombier csr9w(ctlr, Rd|Ss|Scs);
7597dd7cddfSDavid du Colombier csr9w(ctlr, Rd|Ss|Sclk|Scs);
7607dd7cddfSDavid du Colombier csr9w(ctlr, Rd|Ss);
7617dd7cddfSDavid du Colombier
7627dd7cddfSDavid du Colombier op = 0x06;
7637dd7cddfSDavid du Colombier for(i = 3-1; i >= 0; i--){
7647dd7cddfSDavid du Colombier data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs;
7657dd7cddfSDavid du Colombier csr9w(ctlr, data);
7667dd7cddfSDavid du Colombier csr9w(ctlr, data|Sclk);
7677dd7cddfSDavid du Colombier csr9w(ctlr, data);
7687dd7cddfSDavid du Colombier }
7697dd7cddfSDavid du Colombier
7709a747e4fSDavid du Colombier /*
7719a747e4fSDavid du Colombier * First time through must work out the EEPROM size.
772f43e6a25SDavid du Colombier * This doesn't seem to work on the 21041 as implemented
773f43e6a25SDavid du Colombier * in Virtual PC for the Mac, so wire any 21041 to 6,
774f43e6a25SDavid du Colombier * it's the only 21041 this code will ever likely see.
7759a747e4fSDavid du Colombier */
776f43e6a25SDavid du Colombier if((size = ctlr->sromsz) == 0){
777f43e6a25SDavid du Colombier if(ctlr->id == Tulip1)
778f43e6a25SDavid du Colombier ctlr->sromsz = size = 6;
779f43e6a25SDavid du Colombier else
7809a747e4fSDavid du Colombier size = 8;
781f43e6a25SDavid du Colombier }
7829a747e4fSDavid du Colombier
7839a747e4fSDavid du Colombier for(size = size-1; size >= 0; size--){
7849a747e4fSDavid du Colombier data = Rd|Ss|(((r>>size) & 0x01)<<2)|Scs;
7857dd7cddfSDavid du Colombier csr9w(ctlr, data);
7867dd7cddfSDavid du Colombier csr9w(ctlr, data|Sclk);
7877dd7cddfSDavid du Colombier csr9w(ctlr, data);
7889a747e4fSDavid du Colombier microdelay(1);
789f43e6a25SDavid du Colombier if(ctlr->sromsz == 0 && !(csr32r(ctlr, 9) & Sdo))
7909a747e4fSDavid du Colombier break;
7917dd7cddfSDavid du Colombier }
7927dd7cddfSDavid du Colombier
7937dd7cddfSDavid du Colombier data = 0;
7947dd7cddfSDavid du Colombier for(i = 16-1; i >= 0; i--){
7957dd7cddfSDavid du Colombier csr9w(ctlr, Rd|Ss|Sclk|Scs);
7967dd7cddfSDavid du Colombier if(csr32r(ctlr, 9) & Sdo)
7977dd7cddfSDavid du Colombier data |= (1<<i);
7987dd7cddfSDavid du Colombier csr9w(ctlr, Rd|Ss|Scs);
7997dd7cddfSDavid du Colombier }
8007dd7cddfSDavid du Colombier
8017dd7cddfSDavid du Colombier csr9w(ctlr, 0);
8027dd7cddfSDavid du Colombier
8039a747e4fSDavid du Colombier if(ctlr->sromsz == 0){
8049a747e4fSDavid du Colombier ctlr->sromsz = 8-size;
8059a747e4fSDavid du Colombier goto reread;
8069a747e4fSDavid du Colombier }
8079a747e4fSDavid du Colombier
8087dd7cddfSDavid du Colombier return data & 0xFFFF;
8097dd7cddfSDavid du Colombier }
8107dd7cddfSDavid du Colombier
8117dd7cddfSDavid du Colombier static void
shutdown(Ether * ether)8120809e9a7SDavid du Colombier shutdown(Ether* ether)
8130809e9a7SDavid du Colombier {
8140809e9a7SDavid du Colombier Ctlr *ctlr = ether->ctlr;
8150809e9a7SDavid du Colombier
8160809e9a7SDavid du Colombier print("ether2114x shutting down\n");
8170809e9a7SDavid du Colombier csr32w(ctlr, 0, Swr);
8180809e9a7SDavid du Colombier }
8190809e9a7SDavid du Colombier
8200809e9a7SDavid du Colombier static void
softreset(Ctlr * ctlr)8217dd7cddfSDavid du Colombier softreset(Ctlr* ctlr)
8227dd7cddfSDavid du Colombier {
8237dd7cddfSDavid du Colombier /*
8247dd7cddfSDavid du Colombier * Soft-reset the controller and initialise bus mode.
8257dd7cddfSDavid du Colombier * Delay should be >= 50 PCI cycles (2×S @ 25MHz).
8267dd7cddfSDavid du Colombier */
8277dd7cddfSDavid du Colombier csr32w(ctlr, 0, Swr);
8287dd7cddfSDavid du Colombier microdelay(10);
8297dd7cddfSDavid du Colombier csr32w(ctlr, 0, Rml|Cal16);
8307dd7cddfSDavid du Colombier delay(1);
8317dd7cddfSDavid du Colombier }
8327dd7cddfSDavid du Colombier
8337dd7cddfSDavid du Colombier static int
type5block(Ctlr * ctlr,uchar * block)8347dd7cddfSDavid du Colombier type5block(Ctlr* ctlr, uchar* block)
8357dd7cddfSDavid du Colombier {
8367dd7cddfSDavid du Colombier int csr15, i, len;
8377dd7cddfSDavid du Colombier
8387dd7cddfSDavid du Colombier /*
8397dd7cddfSDavid du Colombier * Reset or GPR sequence. Reset should be once only,
8407dd7cddfSDavid du Colombier * before the GPR sequence.
8417dd7cddfSDavid du Colombier * Note 'block' is not a pointer to the block head but
8427dd7cddfSDavid du Colombier * a pointer to the data in the block starting at the
8437dd7cddfSDavid du Colombier * reset length value so type5block can be used for the
8447dd7cddfSDavid du Colombier * sequences contained in type 1 and type 3 blocks.
8457dd7cddfSDavid du Colombier * The SROM docs state the 21140 type 5 block is the
8467dd7cddfSDavid du Colombier * same as that for the 21143, but the two controllers
8477dd7cddfSDavid du Colombier * use different registers and sequence-element lengths
8487dd7cddfSDavid du Colombier * so the 21140 code here is a guess for a real type 5
8497dd7cddfSDavid du Colombier * sequence.
8507dd7cddfSDavid du Colombier */
8517dd7cddfSDavid du Colombier len = *block++;
85259cc4ca5SDavid du Colombier if(ctlr->id != Tulip3){
8537dd7cddfSDavid du Colombier for(i = 0; i < len; i++){
8547dd7cddfSDavid du Colombier csr32w(ctlr, 12, *block);
8557dd7cddfSDavid du Colombier block++;
8567dd7cddfSDavid du Colombier }
8577dd7cddfSDavid du Colombier return len;
8587dd7cddfSDavid du Colombier }
8597dd7cddfSDavid du Colombier
8607dd7cddfSDavid du Colombier for(i = 0; i < len; i++){
8617dd7cddfSDavid du Colombier csr15 = *block++<<16;
8627dd7cddfSDavid du Colombier csr15 |= *block++<<24;
8637dd7cddfSDavid du Colombier csr32w(ctlr, 15, csr15);
8647dd7cddfSDavid du Colombier debug("%8.8uX ", csr15);
8657dd7cddfSDavid du Colombier }
8667dd7cddfSDavid du Colombier return 2*len;
8677dd7cddfSDavid du Colombier }
8687dd7cddfSDavid du Colombier
8697dd7cddfSDavid du Colombier static int
typephylink(Ctlr * ctlr,uchar *)8707dd7cddfSDavid du Colombier typephylink(Ctlr* ctlr, uchar*)
8717dd7cddfSDavid du Colombier {
8727dd7cddfSDavid du Colombier int an, bmcr, bmsr, csr6, x;
8737dd7cddfSDavid du Colombier
8747dd7cddfSDavid du Colombier /*
8757dd7cddfSDavid du Colombier * Fail if
8767dd7cddfSDavid du Colombier * auto-negotiataion enabled but not complete;
8777dd7cddfSDavid du Colombier * no valid link established.
8787dd7cddfSDavid du Colombier */
8797dd7cddfSDavid du Colombier bmcr = miir(ctlr, ctlr->curphyad, Bmcr);
8807dd7cddfSDavid du Colombier miir(ctlr, ctlr->curphyad, Bmsr);
8817dd7cddfSDavid du Colombier bmsr = miir(ctlr, ctlr->curphyad, Bmsr);
8827dd7cddfSDavid du Colombier debug("bmcr 0x%2.2uX bmsr 0x%2.2uX\n", bmcr, bmsr);
8837dd7cddfSDavid du Colombier if(((bmcr & 0x1000) && !(bmsr & 0x0020)) || !(bmsr & 0x0004))
8847dd7cddfSDavid du Colombier return 0;
8857dd7cddfSDavid du Colombier
8867dd7cddfSDavid du Colombier if(bmcr & 0x1000){
8877dd7cddfSDavid du Colombier an = miir(ctlr, ctlr->curphyad, Anar);
8887dd7cddfSDavid du Colombier an &= miir(ctlr, ctlr->curphyad, Anlpar) & 0x3E0;
8897dd7cddfSDavid du Colombier debug("an 0x%2.uX 0x%2.2uX 0x%2.2uX\n",
8907dd7cddfSDavid du Colombier miir(ctlr, ctlr->curphyad, Anar),
8917dd7cddfSDavid du Colombier miir(ctlr, ctlr->curphyad, Anlpar),
8927dd7cddfSDavid du Colombier an);
8937dd7cddfSDavid du Colombier
8947dd7cddfSDavid du Colombier if(an & 0x0100)
8957dd7cddfSDavid du Colombier x = 0x4000;
8967dd7cddfSDavid du Colombier else if(an & 0x0080)
8977dd7cddfSDavid du Colombier x = 0x2000;
8987dd7cddfSDavid du Colombier else if(an & 0x0040)
8997dd7cddfSDavid du Colombier x = 0x1000;
9007dd7cddfSDavid du Colombier else if(an & 0x0020)
9017dd7cddfSDavid du Colombier x = 0x0800;
9027dd7cddfSDavid du Colombier else
9037dd7cddfSDavid du Colombier x = 0;
9047dd7cddfSDavid du Colombier }
9057dd7cddfSDavid du Colombier else if((bmcr & 0x2100) == 0x2100)
9067dd7cddfSDavid du Colombier x = 0x4000;
9077dd7cddfSDavid du Colombier else if(bmcr & 0x2000){
9087dd7cddfSDavid du Colombier /*
9097dd7cddfSDavid du Colombier * If FD capable, force it if necessary.
9107dd7cddfSDavid du Colombier */
9117dd7cddfSDavid du Colombier if((bmsr & 0x4000) && ctlr->fd){
9127dd7cddfSDavid du Colombier miiw(ctlr, ctlr->curphyad, Bmcr, 0x2100);
9137dd7cddfSDavid du Colombier x = 0x4000;
9147dd7cddfSDavid du Colombier }
9157dd7cddfSDavid du Colombier else
9167dd7cddfSDavid du Colombier x = 0x2000;
9177dd7cddfSDavid du Colombier }
9187dd7cddfSDavid du Colombier else if(bmcr & 0x0100)
9197dd7cddfSDavid du Colombier x = 0x1000;
9207dd7cddfSDavid du Colombier else
9217dd7cddfSDavid du Colombier x = 0x0800;
9227dd7cddfSDavid du Colombier
923f43e6a25SDavid du Colombier csr6 = Sc|Mbo|Hbd|Ps|Ca|TrMODE|Sb;
9247dd7cddfSDavid du Colombier if(ctlr->fdx & x)
9257dd7cddfSDavid du Colombier csr6 |= Fd;
9267dd7cddfSDavid du Colombier if(ctlr->ttm & x)
9277dd7cddfSDavid du Colombier csr6 |= Ttm;
9287dd7cddfSDavid du Colombier debug("csr6 0x%8.8uX 0x%8.8uX 0x%8.8luX\n",
9297dd7cddfSDavid du Colombier csr6, ctlr->csr6, csr32r(ctlr, 6));
9307dd7cddfSDavid du Colombier if(csr6 != ctlr->csr6){
9317dd7cddfSDavid du Colombier ctlr->csr6 = csr6;
9327dd7cddfSDavid du Colombier csr32w(ctlr, 6, csr6);
9337dd7cddfSDavid du Colombier }
9347dd7cddfSDavid du Colombier
9357dd7cddfSDavid du Colombier return 1;
9367dd7cddfSDavid du Colombier }
9377dd7cddfSDavid du Colombier
9387dd7cddfSDavid du Colombier static int
typephymode(Ctlr * ctlr,uchar * block,int wait)9397dd7cddfSDavid du Colombier typephymode(Ctlr* ctlr, uchar* block, int wait)
9407dd7cddfSDavid du Colombier {
9417dd7cddfSDavid du Colombier uchar *p;
9427dd7cddfSDavid du Colombier int len, mc, nway, phyx, timeo;
9437dd7cddfSDavid du Colombier
9447dd7cddfSDavid du Colombier if(DEBUG){
9457dd7cddfSDavid du Colombier int i;
9467dd7cddfSDavid du Colombier
9477dd7cddfSDavid du Colombier len = (block[0] & ~0x80)+1;
9487dd7cddfSDavid du Colombier for(i = 0; i < len; i++)
9497dd7cddfSDavid du Colombier debug("%2.2uX ", block[i]);
9507dd7cddfSDavid du Colombier debug("\n");
9517dd7cddfSDavid du Colombier }
9527dd7cddfSDavid du Colombier
9537dd7cddfSDavid du Colombier if(block[1] == 1)
9547dd7cddfSDavid du Colombier len = 1;
9557dd7cddfSDavid du Colombier else if(block[1] == 3)
9567dd7cddfSDavid du Colombier len = 2;
9577dd7cddfSDavid du Colombier else
9587dd7cddfSDavid du Colombier return -1;
9597dd7cddfSDavid du Colombier
9607dd7cddfSDavid du Colombier /*
9617dd7cddfSDavid du Colombier * Snarf the media capabilities, nway advertisment,
9627dd7cddfSDavid du Colombier * FDX and TTM bitmaps.
9637dd7cddfSDavid du Colombier */
9647dd7cddfSDavid du Colombier p = &block[5+len*block[3]+len*block[4+len*block[3]]];
9657dd7cddfSDavid du Colombier mc = *p++;
9667dd7cddfSDavid du Colombier mc |= *p++<<8;
9677dd7cddfSDavid du Colombier nway = *p++;
9687dd7cddfSDavid du Colombier nway |= *p++<<8;
9697dd7cddfSDavid du Colombier ctlr->fdx = *p++;
9707dd7cddfSDavid du Colombier ctlr->fdx |= *p++<<8;
9717dd7cddfSDavid du Colombier ctlr->ttm = *p++;
9727dd7cddfSDavid du Colombier ctlr->ttm |= *p<<8;
9737dd7cddfSDavid du Colombier debug("mc %4.4uX nway %4.4uX fdx %4.4uX ttm %4.4uX\n",
9747dd7cddfSDavid du Colombier mc, nway, ctlr->fdx, ctlr->ttm);
9757dd7cddfSDavid du Colombier USED(mc);
9767dd7cddfSDavid du Colombier
9777dd7cddfSDavid du Colombier phyx = block[2];
9787dd7cddfSDavid du Colombier ctlr->curphyad = ctlr->phy[phyx];
9797dd7cddfSDavid du Colombier
98041dd6b47SDavid du Colombier ctlr->csr6 = 0; /* Sc|Mbo|Hbd|Ps|Ca|TrMODE|Sb; */
9817dd7cddfSDavid du Colombier // csr32w(ctlr, 6, ctlr->csr6);
9827dd7cddfSDavid du Colombier if(typephylink(ctlr, block))
9837dd7cddfSDavid du Colombier return 0;
9847dd7cddfSDavid du Colombier
9857dd7cddfSDavid du Colombier if(!(ctlr->phyreset & (1<<phyx))){
9867dd7cddfSDavid du Colombier debug("reset seq: len %d: ", block[3]);
9877dd7cddfSDavid du Colombier if(ctlr->type5block)
9887dd7cddfSDavid du Colombier type5block(ctlr, &ctlr->type5block[2]);
9897dd7cddfSDavid du Colombier else
9907dd7cddfSDavid du Colombier type5block(ctlr, &block[4+len*block[3]]);
9917dd7cddfSDavid du Colombier debug("\n");
9927dd7cddfSDavid du Colombier ctlr->phyreset |= (1<<phyx);
9937dd7cddfSDavid du Colombier }
9947dd7cddfSDavid du Colombier
9957dd7cddfSDavid du Colombier /*
9967dd7cddfSDavid du Colombier * GPR sequence.
9977dd7cddfSDavid du Colombier */
9987dd7cddfSDavid du Colombier debug("gpr seq: len %d: ", block[3]);
9997dd7cddfSDavid du Colombier type5block(ctlr, &block[3]);
10007dd7cddfSDavid du Colombier debug("\n");
10017dd7cddfSDavid du Colombier
100241dd6b47SDavid du Colombier ctlr->csr6 = 0; /* Sc|Mbo|Hbd|Ps|Ca|TrMODE|Sb; */
10037dd7cddfSDavid du Colombier // csr32w(ctlr, 6, ctlr->csr6);
10047dd7cddfSDavid du Colombier if(typephylink(ctlr, block))
10057dd7cddfSDavid du Colombier return 0;
10067dd7cddfSDavid du Colombier
10077dd7cddfSDavid du Colombier /*
10087dd7cddfSDavid du Colombier * Turn off auto-negotiation, set the auto-negotiation
10097dd7cddfSDavid du Colombier * advertisment register then start the auto-negotiation
10107dd7cddfSDavid du Colombier * process again.
10117dd7cddfSDavid du Colombier */
10127dd7cddfSDavid du Colombier miiw(ctlr, ctlr->curphyad, Bmcr, 0);
10137dd7cddfSDavid du Colombier miiw(ctlr, ctlr->curphyad, Anar, nway|1);
10147dd7cddfSDavid du Colombier miiw(ctlr, ctlr->curphyad, Bmcr, 0x1000);
10157dd7cddfSDavid du Colombier
10167dd7cddfSDavid du Colombier if(!wait)
10177dd7cddfSDavid du Colombier return 0;
10187dd7cddfSDavid du Colombier
1019d9306527SDavid du Colombier for(timeo = 0; timeo < 45; timeo++){
10207dd7cddfSDavid du Colombier if(typephylink(ctlr, block))
10217dd7cddfSDavid du Colombier return 0;
10227dd7cddfSDavid du Colombier delay(100);
10237dd7cddfSDavid du Colombier }
10247dd7cddfSDavid du Colombier
10257dd7cddfSDavid du Colombier return -1;
10267dd7cddfSDavid du Colombier }
10277dd7cddfSDavid du Colombier
10287dd7cddfSDavid du Colombier static int
typesymmode(Ctlr * ctlr,uchar * block,int wait)10299a747e4fSDavid du Colombier typesymmode(Ctlr *ctlr, uchar *block, int wait)
10309a747e4fSDavid du Colombier {
10319a747e4fSDavid du Colombier uint gpmode, gpdata, command;
10329a747e4fSDavid du Colombier
10339a747e4fSDavid du Colombier USED(wait);
10349a747e4fSDavid du Colombier gpmode = block[3] | ((uint) block[4] << 8);
10359a747e4fSDavid du Colombier gpdata = block[5] | ((uint) block[6] << 8);
10369a747e4fSDavid du Colombier command = (block[7] | ((uint) block[8] << 8)) & 0x71;
10379a747e4fSDavid du Colombier if (command & 0x8000) {
10389a747e4fSDavid du Colombier print("ether2114x.c: FIXME: handle type 4 mode blocks where cmd.active_invalid != 0\n");
10399a747e4fSDavid du Colombier return -1;
10409a747e4fSDavid du Colombier }
10419a747e4fSDavid du Colombier csr32w(ctlr, 15, gpmode);
10429a747e4fSDavid du Colombier csr32w(ctlr, 15, gpdata);
10439a747e4fSDavid du Colombier ctlr->csr6 = (command & 0x71) << 18;
10449a747e4fSDavid du Colombier csr32w(ctlr, 6, ctlr->csr6);
10459a747e4fSDavid du Colombier return 0;
10469a747e4fSDavid du Colombier }
10479a747e4fSDavid du Colombier
10489a747e4fSDavid du Colombier static int
type2mode(Ctlr * ctlr,uchar * block,int)10499a747e4fSDavid du Colombier type2mode(Ctlr* ctlr, uchar* block, int)
10509a747e4fSDavid du Colombier {
10519a747e4fSDavid du Colombier uchar *p;
10529a747e4fSDavid du Colombier int csr6, csr13, csr14, csr15, gpc, gpd;
10539a747e4fSDavid du Colombier
1054f43e6a25SDavid du Colombier csr6 = Sc|Mbo|Ca|TrMODE|Sb;
10559a747e4fSDavid du Colombier debug("type2mode: medium 0x%2.2uX\n", block[2]);
10569a747e4fSDavid du Colombier
10579a747e4fSDavid du Colombier /*
10589a747e4fSDavid du Colombier * Don't attempt full-duplex
10599a747e4fSDavid du Colombier * unless explicitly requested.
10609a747e4fSDavid du Colombier */
10619a747e4fSDavid du Colombier if((block[2] & 0x3F) == 0x04){ /* 10BASE-TFD */
10629a747e4fSDavid du Colombier if(!ctlr->fd)
10639a747e4fSDavid du Colombier return -1;
10649a747e4fSDavid du Colombier csr6 |= Fd;
10659a747e4fSDavid du Colombier }
10669a747e4fSDavid du Colombier
10679a747e4fSDavid du Colombier /*
10689a747e4fSDavid du Colombier * Operating mode programming values from the datasheet
10699a747e4fSDavid du Colombier * unless media specific data is explicitly given.
10709a747e4fSDavid du Colombier */
10719a747e4fSDavid du Colombier p = &block[3];
10729a747e4fSDavid du Colombier if(block[2] & 0x40){
10739a747e4fSDavid du Colombier csr13 = (block[4]<<8)|block[3];
10749a747e4fSDavid du Colombier csr14 = (block[6]<<8)|block[5];
10759a747e4fSDavid du Colombier csr15 = (block[8]<<8)|block[7];
10769a747e4fSDavid du Colombier p += 6;
10779a747e4fSDavid du Colombier }
10789a747e4fSDavid du Colombier else switch(block[2] & 0x3F){
10799a747e4fSDavid du Colombier default:
10809a747e4fSDavid du Colombier return -1;
10819a747e4fSDavid du Colombier case 0x00: /* 10BASE-T */
10829a747e4fSDavid du Colombier csr13 = 0x00000001;
10839a747e4fSDavid du Colombier csr14 = 0x00007F3F;
10849a747e4fSDavid du Colombier csr15 = 0x00000008;
10859a747e4fSDavid du Colombier break;
10869a747e4fSDavid du Colombier case 0x01: /* 10BASE-2 */
10879a747e4fSDavid du Colombier csr13 = 0x00000009;
10889a747e4fSDavid du Colombier csr14 = 0x00000705;
10899a747e4fSDavid du Colombier csr15 = 0x00000006;
10909a747e4fSDavid du Colombier break;
10919a747e4fSDavid du Colombier case 0x02: /* 10BASE-5 (AUI) */
10929a747e4fSDavid du Colombier csr13 = 0x00000009;
10939a747e4fSDavid du Colombier csr14 = 0x00000705;
10949a747e4fSDavid du Colombier csr15 = 0x0000000E;
10959a747e4fSDavid du Colombier break;
10969a747e4fSDavid du Colombier case 0x04: /* 10BASE-TFD */
10979a747e4fSDavid du Colombier csr13 = 0x00000001;
10989a747e4fSDavid du Colombier csr14 = 0x00007F3D;
10999a747e4fSDavid du Colombier csr15 = 0x00000008;
11009a747e4fSDavid du Colombier break;
11019a747e4fSDavid du Colombier }
11029a747e4fSDavid du Colombier gpc = *p++<<16;
11039a747e4fSDavid du Colombier gpc |= *p++<<24;
11049a747e4fSDavid du Colombier gpd = *p++<<16;
11059a747e4fSDavid du Colombier gpd |= *p<<24;
11069a747e4fSDavid du Colombier
11079a747e4fSDavid du Colombier csr32w(ctlr, 13, 0);
11089a747e4fSDavid du Colombier csr32w(ctlr, 14, csr14);
11099a747e4fSDavid du Colombier csr32w(ctlr, 15, gpc|csr15);
11109a747e4fSDavid du Colombier delay(10);
11119a747e4fSDavid du Colombier csr32w(ctlr, 15, gpd|csr15);
11129a747e4fSDavid du Colombier csr32w(ctlr, 13, csr13);
11139a747e4fSDavid du Colombier
11149a747e4fSDavid du Colombier ctlr->csr6 = csr6;
11159a747e4fSDavid du Colombier csr32w(ctlr, 6, ctlr->csr6);
11169a747e4fSDavid du Colombier
11179a747e4fSDavid du Colombier debug("type2mode: csr13 %8.8uX csr14 %8.8uX csr15 %8.8uX\n",
11189a747e4fSDavid du Colombier csr13, csr14, csr15);
11199a747e4fSDavid du Colombier debug("type2mode: gpc %8.8uX gpd %8.8uX csr6 %8.8uX\n",
11209a747e4fSDavid du Colombier gpc, gpd, csr6);
11219a747e4fSDavid du Colombier
11229a747e4fSDavid du Colombier return 0;
11239a747e4fSDavid du Colombier }
11249a747e4fSDavid du Colombier
11259a747e4fSDavid du Colombier static int
type0link(Ctlr * ctlr,uchar * block)11267dd7cddfSDavid du Colombier type0link(Ctlr* ctlr, uchar* block)
11277dd7cddfSDavid du Colombier {
11287dd7cddfSDavid du Colombier int m, polarity, sense;
11297dd7cddfSDavid du Colombier
11307dd7cddfSDavid du Colombier m = (block[3]<<8)|block[2];
11317dd7cddfSDavid du Colombier sense = 1<<((m & 0x000E)>>1);
11327dd7cddfSDavid du Colombier if(m & 0x0080)
11337dd7cddfSDavid du Colombier polarity = sense;
11347dd7cddfSDavid du Colombier else
11357dd7cddfSDavid du Colombier polarity = 0;
11367dd7cddfSDavid du Colombier
11377dd7cddfSDavid du Colombier return (csr32r(ctlr, 12) & sense)^polarity;
11387dd7cddfSDavid du Colombier }
11397dd7cddfSDavid du Colombier
11407dd7cddfSDavid du Colombier static int
type0mode(Ctlr * ctlr,uchar * block,int wait)11417dd7cddfSDavid du Colombier type0mode(Ctlr* ctlr, uchar* block, int wait)
11427dd7cddfSDavid du Colombier {
11437dd7cddfSDavid du Colombier int csr6, m, timeo;
11447dd7cddfSDavid du Colombier
1145f43e6a25SDavid du Colombier csr6 = Sc|Mbo|Hbd|Ca|TrMODE|Sb;
11467dd7cddfSDavid du Colombier debug("type0: medium 0x%uX, fd %d: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
11477dd7cddfSDavid du Colombier ctlr->medium, ctlr->fd, block[0], block[1], block[2], block[3]);
11487dd7cddfSDavid du Colombier switch(block[0]){
11497dd7cddfSDavid du Colombier default:
11507dd7cddfSDavid du Colombier break;
11517dd7cddfSDavid du Colombier
11527dd7cddfSDavid du Colombier case 0x04: /* 10BASE-TFD */
11537dd7cddfSDavid du Colombier case 0x05: /* 100BASE-TXFD */
11547dd7cddfSDavid du Colombier case 0x08: /* 100BASE-FXFD */
11557dd7cddfSDavid du Colombier /*
11567dd7cddfSDavid du Colombier * Don't attempt full-duplex
11577dd7cddfSDavid du Colombier * unless explicitly requested.
11587dd7cddfSDavid du Colombier */
11597dd7cddfSDavid du Colombier if(!ctlr->fd)
11607dd7cddfSDavid du Colombier return -1;
11617dd7cddfSDavid du Colombier csr6 |= Fd;
11627dd7cddfSDavid du Colombier break;
11637dd7cddfSDavid du Colombier }
11647dd7cddfSDavid du Colombier
11657dd7cddfSDavid du Colombier m = (block[3]<<8)|block[2];
11667dd7cddfSDavid du Colombier if(m & 0x0001)
11677dd7cddfSDavid du Colombier csr6 |= Ps;
11687dd7cddfSDavid du Colombier if(m & 0x0010)
11697dd7cddfSDavid du Colombier csr6 |= Ttm;
11707dd7cddfSDavid du Colombier if(m & 0x0020)
11717dd7cddfSDavid du Colombier csr6 |= Pcs;
11727dd7cddfSDavid du Colombier if(m & 0x0040)
11737dd7cddfSDavid du Colombier csr6 |= Scr;
11747dd7cddfSDavid du Colombier
11757dd7cddfSDavid du Colombier csr32w(ctlr, 12, block[1]);
11767dd7cddfSDavid du Colombier microdelay(10);
11777dd7cddfSDavid du Colombier csr32w(ctlr, 6, csr6);
11787dd7cddfSDavid du Colombier ctlr->csr6 = csr6;
11797dd7cddfSDavid du Colombier
11807dd7cddfSDavid du Colombier if(!wait)
11817dd7cddfSDavid du Colombier return 0;
11827dd7cddfSDavid du Colombier
11837dd7cddfSDavid du Colombier for(timeo = 0; timeo < 30; timeo++){
11847dd7cddfSDavid du Colombier if(type0link(ctlr, block))
11857dd7cddfSDavid du Colombier return 0;
11867dd7cddfSDavid du Colombier delay(100);
11877dd7cddfSDavid du Colombier }
11887dd7cddfSDavid du Colombier
11897dd7cddfSDavid du Colombier return -1;
11907dd7cddfSDavid du Colombier }
11917dd7cddfSDavid du Colombier
11927dd7cddfSDavid du Colombier static int
media21041(Ether * ether,int wait)1193f43e6a25SDavid du Colombier media21041(Ether* ether, int wait)
1194f43e6a25SDavid du Colombier {
1195f43e6a25SDavid du Colombier Ctlr* ctlr;
1196f43e6a25SDavid du Colombier uchar *block;
1197f43e6a25SDavid du Colombier int csr6, csr13, csr14, csr15, medium, timeo;
1198f43e6a25SDavid du Colombier
1199f43e6a25SDavid du Colombier ctlr = ether->ctlr;
1200f43e6a25SDavid du Colombier block = ctlr->infoblock[ctlr->curk];
1201f43e6a25SDavid du Colombier debug("media21041: block[0] %2.2uX, medium %4.4uX sct %4.4uX\n",
1202f43e6a25SDavid du Colombier block[0], ctlr->medium, ctlr->sct);
1203f43e6a25SDavid du Colombier
1204f43e6a25SDavid du Colombier medium = block[0] & 0x3F;
1205f43e6a25SDavid du Colombier if(ctlr->medium >= 0 && medium != ctlr->medium)
1206f43e6a25SDavid du Colombier return 0;
1207f43e6a25SDavid du Colombier if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != medium)
1208f43e6a25SDavid du Colombier return 0;
1209f43e6a25SDavid du Colombier
1210f43e6a25SDavid du Colombier csr6 = Sc|Mbo|Ca|TrMODE|Sb;
1211f43e6a25SDavid du Colombier if(block[0] & 0x40){
1212f43e6a25SDavid du Colombier csr13 = (block[2]<<8)|block[1];
1213f43e6a25SDavid du Colombier csr14 = (block[4]<<8)|block[3];
1214f43e6a25SDavid du Colombier csr15 = (block[6]<<8)|block[5];
1215f43e6a25SDavid du Colombier }
1216f43e6a25SDavid du Colombier else switch(medium){
1217f43e6a25SDavid du Colombier default:
1218f43e6a25SDavid du Colombier return -1;
1219f43e6a25SDavid du Colombier case 0x00: /* 10BASE-T */
1220f43e6a25SDavid du Colombier csr13 = 0xEF01;
1221f43e6a25SDavid du Colombier csr14 = 0xFF3F;
1222f43e6a25SDavid du Colombier csr15 = 0x0008;
1223f43e6a25SDavid du Colombier break;
1224f43e6a25SDavid du Colombier case 0x01: /* 10BASE-2 */
1225f43e6a25SDavid du Colombier csr13 = 0xEF09;
1226f43e6a25SDavid du Colombier csr14 = 0xF73D;
1227f43e6a25SDavid du Colombier csr15 = 0x0006;
1228f43e6a25SDavid du Colombier break;
1229f43e6a25SDavid du Colombier case 0x02: /* 10BASE-5 */
1230f43e6a25SDavid du Colombier csr13 = 0xEF09;
1231f43e6a25SDavid du Colombier csr14 = 0xF73D;
1232f43e6a25SDavid du Colombier csr15 = 0x000E;
1233f43e6a25SDavid du Colombier break;
1234f43e6a25SDavid du Colombier case 0x04: /* 10BASE-TFD */
1235f43e6a25SDavid du Colombier csr13 = 0xEF01;
1236f43e6a25SDavid du Colombier csr14 = 0xFF3D;
1237f43e6a25SDavid du Colombier csr15 = 0x0008;
1238f43e6a25SDavid du Colombier break;
1239f43e6a25SDavid du Colombier }
1240f43e6a25SDavid du Colombier
1241f43e6a25SDavid du Colombier csr32w(ctlr, 13, 0);
1242f43e6a25SDavid du Colombier csr32w(ctlr, 14, csr14);
1243f43e6a25SDavid du Colombier csr32w(ctlr, 15, csr15);
1244f43e6a25SDavid du Colombier csr32w(ctlr, 13, csr13);
1245f43e6a25SDavid du Colombier delay(10);
1246f43e6a25SDavid du Colombier
1247f43e6a25SDavid du Colombier if(medium == 0x04)
1248f43e6a25SDavid du Colombier csr6 |= Fd;
1249f43e6a25SDavid du Colombier ctlr->csr6 = csr6;
1250f43e6a25SDavid du Colombier csr32w(ctlr, 6, ctlr->csr6);
1251f43e6a25SDavid du Colombier
1252f43e6a25SDavid du Colombier debug("media21041: csr6 %8.8uX csr13 %4.4uX csr14 %4.4uX csr15 %4.4uX\n",
1253f43e6a25SDavid du Colombier csr6, csr13, csr14, csr15);
1254f43e6a25SDavid du Colombier
1255f43e6a25SDavid du Colombier if(!wait)
1256f43e6a25SDavid du Colombier return 0;
1257f43e6a25SDavid du Colombier
1258f43e6a25SDavid du Colombier for(timeo = 0; timeo < 30; timeo++){
1259f43e6a25SDavid du Colombier if(!(csr32r(ctlr, 12) & 0x0002)){
1260f43e6a25SDavid du Colombier debug("media21041: ok: csr12 %4.4luX timeo %d\n",
1261f43e6a25SDavid du Colombier csr32r(ctlr, 12), timeo);
1262f43e6a25SDavid du Colombier return 10;
1263f43e6a25SDavid du Colombier }
1264f43e6a25SDavid du Colombier delay(100);
1265f43e6a25SDavid du Colombier }
1266f43e6a25SDavid du Colombier debug("media21041: !ok: csr12 %4.4luX\n", csr32r(ctlr, 12));
1267f43e6a25SDavid du Colombier
1268f43e6a25SDavid du Colombier return -1;
1269f43e6a25SDavid du Colombier }
1270f43e6a25SDavid du Colombier
1271f43e6a25SDavid du Colombier static int
mediaxx(Ether * ether,int wait)12727dd7cddfSDavid du Colombier mediaxx(Ether* ether, int wait)
12737dd7cddfSDavid du Colombier {
12747dd7cddfSDavid du Colombier Ctlr* ctlr;
12757dd7cddfSDavid du Colombier uchar *block;
12767dd7cddfSDavid du Colombier
12777dd7cddfSDavid du Colombier ctlr = ether->ctlr;
12787dd7cddfSDavid du Colombier block = ctlr->infoblock[ctlr->curk];
12797dd7cddfSDavid du Colombier if(block[0] & 0x80){
12807dd7cddfSDavid du Colombier switch(block[1]){
12817dd7cddfSDavid du Colombier default:
12827dd7cddfSDavid du Colombier return -1;
12837dd7cddfSDavid du Colombier case 0:
12847dd7cddfSDavid du Colombier if(ctlr->medium >= 0 && block[2] != ctlr->medium)
12857dd7cddfSDavid du Colombier return 0;
12867dd7cddfSDavid du Colombier /* need this test? */ if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[2])
12877dd7cddfSDavid du Colombier return 0;
12887dd7cddfSDavid du Colombier if(type0mode(ctlr, block+2, wait))
12897dd7cddfSDavid du Colombier return 0;
12907dd7cddfSDavid du Colombier break;
12917dd7cddfSDavid du Colombier case 1:
12927dd7cddfSDavid du Colombier if(typephymode(ctlr, block, wait))
12937dd7cddfSDavid du Colombier return 0;
12947dd7cddfSDavid du Colombier break;
12959a747e4fSDavid du Colombier case 2:
12969a747e4fSDavid du Colombier debug("type2: medium %d block[2] %d\n",
12979a747e4fSDavid du Colombier ctlr->medium, block[2]);
12989a747e4fSDavid du Colombier if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium))
12999a747e4fSDavid du Colombier return 0;
13009a747e4fSDavid du Colombier if(type2mode(ctlr, block, wait))
13019a747e4fSDavid du Colombier return 0;
13029a747e4fSDavid du Colombier break;
13037dd7cddfSDavid du Colombier case 3:
13047dd7cddfSDavid du Colombier if(typephymode(ctlr, block, wait))
13057dd7cddfSDavid du Colombier return 0;
13067dd7cddfSDavid du Colombier break;
13079a747e4fSDavid du Colombier case 4:
13089a747e4fSDavid du Colombier debug("type4: medium %d block[2] %d\n",
13099a747e4fSDavid du Colombier ctlr->medium, block[2]);
13109a747e4fSDavid du Colombier if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium))
13119a747e4fSDavid du Colombier return 0;
13129a747e4fSDavid du Colombier if(typesymmode(ctlr, block, wait))
13139a747e4fSDavid du Colombier return 0;
13149a747e4fSDavid du Colombier break;
13157dd7cddfSDavid du Colombier }
13167dd7cddfSDavid du Colombier }
13177dd7cddfSDavid du Colombier else{
13187dd7cddfSDavid du Colombier if(ctlr->medium >= 0 && block[0] != ctlr->medium)
13197dd7cddfSDavid du Colombier return 0;
13207dd7cddfSDavid du Colombier /* need this test? */if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[0])
13217dd7cddfSDavid du Colombier return 0;
13227dd7cddfSDavid du Colombier if(type0mode(ctlr, block, wait))
13237dd7cddfSDavid du Colombier return 0;
13247dd7cddfSDavid du Colombier }
13257dd7cddfSDavid du Colombier
13267dd7cddfSDavid du Colombier if(ctlr->csr6){
13277dd7cddfSDavid du Colombier if(!(ctlr->csr6 & Ps) || (ctlr->csr6 & Ttm))
13287dd7cddfSDavid du Colombier return 10;
13297dd7cddfSDavid du Colombier return 100;
13307dd7cddfSDavid du Colombier }
13317dd7cddfSDavid du Colombier
13327dd7cddfSDavid du Colombier return 0;
13337dd7cddfSDavid du Colombier }
13347dd7cddfSDavid du Colombier
13357dd7cddfSDavid du Colombier static int
media(Ether * ether,int wait)13367dd7cddfSDavid du Colombier media(Ether* ether, int wait)
13377dd7cddfSDavid du Colombier {
13387dd7cddfSDavid du Colombier Ctlr* ctlr;
13397dd7cddfSDavid du Colombier int k, mbps;
13407dd7cddfSDavid du Colombier
13417dd7cddfSDavid du Colombier ctlr = ether->ctlr;
13427dd7cddfSDavid du Colombier for(k = 0; k < ctlr->k; k++){
1343f43e6a25SDavid du Colombier switch(ctlr->id){
1344f43e6a25SDavid du Colombier default:
13457dd7cddfSDavid du Colombier mbps = mediaxx(ether, wait);
1346f43e6a25SDavid du Colombier break;
1347f43e6a25SDavid du Colombier case Tulip1: /* 21041 */
1348f43e6a25SDavid du Colombier mbps = media21041(ether, wait);
1349f43e6a25SDavid du Colombier break;
1350f43e6a25SDavid du Colombier }
13517dd7cddfSDavid du Colombier if(mbps > 0)
13527dd7cddfSDavid du Colombier return mbps;
13537dd7cddfSDavid du Colombier if(ctlr->curk == 0)
13547dd7cddfSDavid du Colombier ctlr->curk = ctlr->k-1;
13557dd7cddfSDavid du Colombier else
13567dd7cddfSDavid du Colombier ctlr->curk--;
13577dd7cddfSDavid du Colombier }
13587dd7cddfSDavid du Colombier
13597dd7cddfSDavid du Colombier return 0;
13607dd7cddfSDavid du Colombier }
13617dd7cddfSDavid du Colombier
13627dd7cddfSDavid du Colombier static char* mediatable[9] = {
13637dd7cddfSDavid du Colombier "10BASE-T", /* TP */
13647dd7cddfSDavid du Colombier "10BASE-2", /* BNC */
13657dd7cddfSDavid du Colombier "10BASE-5", /* AUI */
13667dd7cddfSDavid du Colombier "100BASE-TX",
13677dd7cddfSDavid du Colombier "10BASE-TFD",
13687dd7cddfSDavid du Colombier "100BASE-TXFD",
13697dd7cddfSDavid du Colombier "100BASE-T4",
13707dd7cddfSDavid du Colombier "100BASE-FX",
13717dd7cddfSDavid du Colombier "100BASE-FXFD",
13727dd7cddfSDavid du Colombier };
13737dd7cddfSDavid du Colombier
13747dd7cddfSDavid du Colombier static uchar en1207[] = { /* Accton EN1207-COMBO */
13757dd7cddfSDavid du Colombier 0x00, 0x00, 0xE8, /* [0] vendor ethernet code */
13767dd7cddfSDavid du Colombier 0x00, /* [3] spare */
13777dd7cddfSDavid du Colombier
13787dd7cddfSDavid du Colombier 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */
13797dd7cddfSDavid du Colombier 0x1F, /* [6] general purpose control */
13807dd7cddfSDavid du Colombier 2, /* [7] block count */
13817dd7cddfSDavid du Colombier
13827dd7cddfSDavid du Colombier 0x00, /* [8] media code (10BASE-TX) */
13837dd7cddfSDavid du Colombier 0x0B, /* [9] general purpose port data */
13847dd7cddfSDavid du Colombier 0x9E, 0x00, /* [10] command (LSB+MSB = 0x009E) */
13857dd7cddfSDavid du Colombier
13867dd7cddfSDavid du Colombier 0x03, /* [8] media code (100BASE-TX) */
13877dd7cddfSDavid du Colombier 0x1B, /* [9] general purpose port data */
13887dd7cddfSDavid du Colombier 0x6D, 0x00, /* [10] command (LSB+MSB = 0x006D) */
13897dd7cddfSDavid du Colombier
13907dd7cddfSDavid du Colombier /* There is 10BASE-2 as well, but... */
13917dd7cddfSDavid du Colombier };
13927dd7cddfSDavid du Colombier
13937dd7cddfSDavid du Colombier static uchar ana6910fx[] = { /* Adaptec (Cogent) ANA-6910FX */
13947dd7cddfSDavid du Colombier 0x00, 0x00, 0x92, /* [0] vendor ethernet code */
13957dd7cddfSDavid du Colombier 0x00, /* [3] spare */
13967dd7cddfSDavid du Colombier
13977dd7cddfSDavid du Colombier 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */
13987dd7cddfSDavid du Colombier 0x3F, /* [6] general purpose control */
13997dd7cddfSDavid du Colombier 1, /* [7] block count */
14007dd7cddfSDavid du Colombier
14017dd7cddfSDavid du Colombier 0x07, /* [8] media code (100BASE-FX) */
14027dd7cddfSDavid du Colombier 0x03, /* [9] general purpose port data */
14037dd7cddfSDavid du Colombier 0x2D, 0x00 /* [10] command (LSB+MSB = 0x000D) */
14047dd7cddfSDavid du Colombier };
14057dd7cddfSDavid du Colombier
14067dd7cddfSDavid du Colombier static uchar smc9332[] = { /* SMC 9332 */
14077dd7cddfSDavid du Colombier 0x00, 0x00, 0xC0, /* [0] vendor ethernet code */
14087dd7cddfSDavid du Colombier 0x00, /* [3] spare */
14097dd7cddfSDavid du Colombier
14107dd7cddfSDavid du Colombier 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */
14117dd7cddfSDavid du Colombier 0x1F, /* [6] general purpose control */
14127dd7cddfSDavid du Colombier 2, /* [7] block count */
14137dd7cddfSDavid du Colombier
14147dd7cddfSDavid du Colombier 0x00, /* [8] media code (10BASE-TX) */
14157dd7cddfSDavid du Colombier 0x00, /* [9] general purpose port data */
14167dd7cddfSDavid du Colombier 0x9E, 0x00, /* [10] command (LSB+MSB = 0x009E) */
14177dd7cddfSDavid du Colombier
14187dd7cddfSDavid du Colombier 0x03, /* [8] media code (100BASE-TX) */
14197dd7cddfSDavid du Colombier 0x09, /* [9] general purpose port data */
14207dd7cddfSDavid du Colombier 0x6D, 0x00, /* [10] command (LSB+MSB = 0x006D) */
14217dd7cddfSDavid du Colombier };
14227dd7cddfSDavid du Colombier
14237dd7cddfSDavid du Colombier static uchar* leaf21140[] = {
14247dd7cddfSDavid du Colombier en1207, /* Accton EN1207-COMBO */
14257dd7cddfSDavid du Colombier ana6910fx, /* Adaptec (Cogent) ANA-6910FX */
14267dd7cddfSDavid du Colombier smc9332, /* SMC 9332 */
14277dd7cddfSDavid du Colombier nil,
14287dd7cddfSDavid du Colombier };
14297dd7cddfSDavid du Colombier
143059cc4ca5SDavid du Colombier /*
143159cc4ca5SDavid du Colombier * Copied to ctlr->srom at offset 20.
143259cc4ca5SDavid du Colombier */
143359cc4ca5SDavid du Colombier static uchar leafpnic[] = {
143459cc4ca5SDavid du Colombier 0x00, 0x00, 0x00, 0x00, /* MAC address */
143559cc4ca5SDavid du Colombier 0x00, 0x00,
143659cc4ca5SDavid du Colombier 0x00, /* controller 0 device number */
143759cc4ca5SDavid du Colombier 0x1E, 0x00, /* controller 0 info leaf offset */
143859cc4ca5SDavid du Colombier 0x00, /* reserved */
143959cc4ca5SDavid du Colombier 0x00, 0x08, /* selected connection type */
144059cc4ca5SDavid du Colombier 0x00, /* general purpose control */
144159cc4ca5SDavid du Colombier 0x01, /* block count */
144259cc4ca5SDavid du Colombier
144359cc4ca5SDavid du Colombier 0x8C, /* format indicator and count */
144459cc4ca5SDavid du Colombier 0x01, /* block type */
144559cc4ca5SDavid du Colombier 0x00, /* PHY number */
144659cc4ca5SDavid du Colombier 0x00, /* GPR sequence length */
144759cc4ca5SDavid du Colombier 0x00, /* reset sequence length */
144859cc4ca5SDavid du Colombier 0x00, 0x78, /* media capabilities */
144959cc4ca5SDavid du Colombier 0xE0, 0x01, /* Nway advertisment */
145059cc4ca5SDavid du Colombier 0x00, 0x50, /* FDX bitmap */
145159cc4ca5SDavid du Colombier 0x00, 0x18, /* TTM bitmap */
145259cc4ca5SDavid du Colombier };
145359cc4ca5SDavid du Colombier
14547dd7cddfSDavid du Colombier static int
srom(Ctlr * ctlr)14557dd7cddfSDavid du Colombier srom(Ctlr* ctlr)
14567dd7cddfSDavid du Colombier {
14577dd7cddfSDavid du Colombier int i, k, oui, phy, x;
14587dd7cddfSDavid du Colombier uchar *p;
14597dd7cddfSDavid du Colombier
14607dd7cddfSDavid du Colombier /*
14617dd7cddfSDavid du Colombier * This is a partial decoding of the SROM format described in
14627dd7cddfSDavid du Colombier * 'Digital Semiconductor 21X4 Serial ROM Format, Version 4.05,
14637dd7cddfSDavid du Colombier * 2-Mar-98'. Only the 2114[03] are handled, support for other
14647dd7cddfSDavid du Colombier * controllers can be added as needed.
14659a747e4fSDavid du Colombier * Do a dummy read first to get the size and allocate ctlr->srom.
14667dd7cddfSDavid du Colombier */
14679a747e4fSDavid du Colombier sromr(ctlr, 0);
14689a747e4fSDavid du Colombier if(ctlr->srom == nil)
14699a747e4fSDavid du Colombier ctlr->srom = malloc((1<<ctlr->sromsz)*sizeof(ushort));
1470aa72973aSDavid du Colombier if(ctlr->srom == nil)
1471aa72973aSDavid du Colombier error(Enomem);
14729a747e4fSDavid du Colombier for(i = 0; i < (1<<ctlr->sromsz); i++){
14737dd7cddfSDavid du Colombier x = sromr(ctlr, i);
14747dd7cddfSDavid du Colombier ctlr->srom[2*i] = x;
14757dd7cddfSDavid du Colombier ctlr->srom[2*i+1] = x>>8;
14767dd7cddfSDavid du Colombier }
14777dd7cddfSDavid du Colombier
1478f43e6a25SDavid du Colombier if(DEBUG){
1479f43e6a25SDavid du Colombier print("srom:");
1480f43e6a25SDavid du Colombier for(i = 0; i < ((1<<ctlr->sromsz)*sizeof(ushort)); i++){
1481f43e6a25SDavid du Colombier if(i && ((i & 0x0F) == 0))
1482f43e6a25SDavid du Colombier print("\n ");
1483f43e6a25SDavid du Colombier print(" %2.2uX", ctlr->srom[i]);
1484f43e6a25SDavid du Colombier }
1485f43e6a25SDavid du Colombier print("\n");
1486f43e6a25SDavid du Colombier }
1487f43e6a25SDavid du Colombier
14887dd7cddfSDavid du Colombier /*
1489d9306527SDavid du Colombier * There are at least 2 SROM layouts:
14907dd7cddfSDavid du Colombier * e.g. Digital EtherWORKS station address at offset 20;
14917dd7cddfSDavid du Colombier * this complies with the 21140A SROM
14927dd7cddfSDavid du Colombier * application note from Digital;
14937dd7cddfSDavid du Colombier * e.g. SMC9332 station address at offset 0 followed by
14947dd7cddfSDavid du Colombier * 2 additional bytes, repeated at offset
14957dd7cddfSDavid du Colombier * 6; the 8 bytes are also repeated in
14967dd7cddfSDavid du Colombier * reverse order at offset 8.
14977dd7cddfSDavid du Colombier * To check which it is, read the SROM and check for the repeating
14987dd7cddfSDavid du Colombier * patterns of the non-compliant cards; if that fails use the one at
14997dd7cddfSDavid du Colombier * offset 20.
15007dd7cddfSDavid du Colombier */
15017dd7cddfSDavid du Colombier ctlr->sromea = ctlr->srom;
15027dd7cddfSDavid du Colombier for(i = 0; i < 8; i++){
15037dd7cddfSDavid du Colombier x = ctlr->srom[i];
15047dd7cddfSDavid du Colombier if(x != ctlr->srom[15-i] || x != ctlr->srom[16+i]){
15057dd7cddfSDavid du Colombier ctlr->sromea = &ctlr->srom[20];
15067dd7cddfSDavid du Colombier break;
15077dd7cddfSDavid du Colombier }
15087dd7cddfSDavid du Colombier }
15097dd7cddfSDavid du Colombier
15107dd7cddfSDavid du Colombier /*
1511d9306527SDavid du Colombier * Fake up the SROM for the PNIC and AMDtek.
1512d9306527SDavid du Colombier * They look like a 21140 with a PHY.
1513d9306527SDavid du Colombier * The MAC address is byte-swapped in the orginal
1514d9306527SDavid du Colombier * PNIC SROM data.
151559cc4ca5SDavid du Colombier */
151659cc4ca5SDavid du Colombier if(ctlr->id == Pnic){
151759cc4ca5SDavid du Colombier memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic));
151859cc4ca5SDavid du Colombier for(i = 0; i < Eaddrlen; i += 2){
151959cc4ca5SDavid du Colombier ctlr->srom[20+i] = ctlr->srom[i+1];
152059cc4ca5SDavid du Colombier ctlr->srom[20+i+1] = ctlr->srom[i];
152159cc4ca5SDavid du Colombier }
152259cc4ca5SDavid du Colombier }
1523b4b9fc2fSDavid du Colombier if(ctlr->id == CentaurP || ctlr->id == CentaurPcb){
1524d9306527SDavid du Colombier memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic));
1525d9306527SDavid du Colombier for(i = 0; i < Eaddrlen; i += 2){
1526d9306527SDavid du Colombier ctlr->srom[20+i] = ctlr->srom[8+i];
1527d9306527SDavid du Colombier ctlr->srom[20+i+1] = ctlr->srom[8+i+1];
1528d9306527SDavid du Colombier }
1529d9306527SDavid du Colombier }
153059cc4ca5SDavid du Colombier
153159cc4ca5SDavid du Colombier /*
15327dd7cddfSDavid du Colombier * Next, try to find the info leaf in the SROM for media detection.
15337dd7cddfSDavid du Colombier * If it's a non-conforming card try to match the vendor ethernet code
15347dd7cddfSDavid du Colombier * and point p at a fake info leaf with compact 21140 entries.
15357dd7cddfSDavid du Colombier */
15367dd7cddfSDavid du Colombier if(ctlr->sromea == ctlr->srom){
15377dd7cddfSDavid du Colombier p = nil;
15387dd7cddfSDavid du Colombier for(i = 0; leaf21140[i] != nil; i++){
15397dd7cddfSDavid du Colombier if(memcmp(leaf21140[i], ctlr->sromea, 3) == 0){
15407dd7cddfSDavid du Colombier p = &leaf21140[i][4];
15417dd7cddfSDavid du Colombier break;
15427dd7cddfSDavid du Colombier }
15437dd7cddfSDavid du Colombier }
15447dd7cddfSDavid du Colombier if(p == nil)
15457dd7cddfSDavid du Colombier return -1;
15467dd7cddfSDavid du Colombier }
15477dd7cddfSDavid du Colombier else
15487dd7cddfSDavid du Colombier p = &ctlr->srom[(ctlr->srom[28]<<8)|ctlr->srom[27]];
15497dd7cddfSDavid du Colombier
15507dd7cddfSDavid du Colombier /*
15517dd7cddfSDavid du Colombier * Set up the info needed for later media detection.
15527dd7cddfSDavid du Colombier * For the 21140, set the general-purpose mask in CSR12.
15537dd7cddfSDavid du Colombier * The info block entries are stored in order of increasing
15547dd7cddfSDavid du Colombier * precedence, so detection will work backwards through the
15557dd7cddfSDavid du Colombier * stored indexes into ctlr->srom.
15567dd7cddfSDavid du Colombier * If an entry is found which matches the selected connection
15577dd7cddfSDavid du Colombier * type, save the index. Otherwise, start at the last entry.
15587dd7cddfSDavid du Colombier * If any MII entries are found (type 1 and 3 blocks), scan
15597dd7cddfSDavid du Colombier * for PHYs.
15607dd7cddfSDavid du Colombier */
15617dd7cddfSDavid du Colombier ctlr->leaf = p;
15627dd7cddfSDavid du Colombier ctlr->sct = *p++;
15637dd7cddfSDavid du Colombier ctlr->sct |= *p++<<8;
1564f43e6a25SDavid du Colombier if(ctlr->id != Tulip3 && ctlr->id != Tulip1){
15657dd7cddfSDavid du Colombier csr32w(ctlr, 12, Gpc|*p++);
15667dd7cddfSDavid du Colombier delay(200);
15677dd7cddfSDavid du Colombier }
15687dd7cddfSDavid du Colombier ctlr->k = *p++;
15697dd7cddfSDavid du Colombier if(ctlr->k >= nelem(ctlr->infoblock))
15707dd7cddfSDavid du Colombier ctlr->k = nelem(ctlr->infoblock)-1;
15717dd7cddfSDavid du Colombier ctlr->sctk = ctlr->k-1;
15727dd7cddfSDavid du Colombier phy = 0;
15737dd7cddfSDavid du Colombier for(k = 0; k < ctlr->k; k++){
15747dd7cddfSDavid du Colombier ctlr->infoblock[k] = p;
1575f43e6a25SDavid du Colombier if(ctlr->id == Tulip1){
1576f43e6a25SDavid du Colombier debug("type21041: 0x%2.2uX\n", p[0]);
1577f43e6a25SDavid du Colombier if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF))
1578f43e6a25SDavid du Colombier ctlr->sctk = k;
1579f43e6a25SDavid du Colombier if(*p & 0x40)
1580f43e6a25SDavid du Colombier p += 7;
1581f43e6a25SDavid du Colombier else
1582f43e6a25SDavid du Colombier p += 1;
1583f43e6a25SDavid du Colombier }
15847dd7cddfSDavid du Colombier /*
15857dd7cddfSDavid du Colombier * The RAMIX PMC665 has a badly-coded SROM,
15867dd7cddfSDavid du Colombier * hence the test for 21143 and type 3.
15877dd7cddfSDavid du Colombier */
1588f43e6a25SDavid du Colombier else if((*p & 0x80) || (ctlr->id == Tulip3 && *(p+1) == 3)){
15897dd7cddfSDavid du Colombier *p |= 0x80;
15907dd7cddfSDavid du Colombier if(*(p+1) == 1 || *(p+1) == 3)
15917dd7cddfSDavid du Colombier phy = 1;
15927dd7cddfSDavid du Colombier if(*(p+1) == 5)
15937dd7cddfSDavid du Colombier ctlr->type5block = p;
15947dd7cddfSDavid du Colombier p += (*p & ~0x80)+1;
15957dd7cddfSDavid du Colombier }
15967dd7cddfSDavid du Colombier else{
15977dd7cddfSDavid du Colombier debug("type0: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n",
15987dd7cddfSDavid du Colombier p[0], p[1], p[2], p[3]);
15997dd7cddfSDavid du Colombier if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF))
16007dd7cddfSDavid du Colombier ctlr->sctk = k;
16017dd7cddfSDavid du Colombier p += 4;
16027dd7cddfSDavid du Colombier }
16037dd7cddfSDavid du Colombier }
16047dd7cddfSDavid du Colombier ctlr->curk = ctlr->sctk;
16057dd7cddfSDavid du Colombier debug("sct 0x%uX medium 0x%uX k %d curk %d phy %d\n",
16067dd7cddfSDavid du Colombier ctlr->sct, ctlr->medium, ctlr->k, ctlr->curk, phy);
16077dd7cddfSDavid du Colombier
16087dd7cddfSDavid du Colombier if(phy){
16097dd7cddfSDavid du Colombier x = 0;
16107dd7cddfSDavid du Colombier for(k = 0; k < nelem(ctlr->phy); k++){
1611b4b9fc2fSDavid du Colombier if((ctlr->id == CentaurP || ctlr->id == CentaurPcb) && k != 1)
1612d9306527SDavid du Colombier continue;
16137dd7cddfSDavid du Colombier if((oui = miir(ctlr, k, 2)) == -1 || oui == 0)
16147dd7cddfSDavid du Colombier continue;
1615d9306527SDavid du Colombier debug("phy reg 2 %4.4uX\n", oui);
16167dd7cddfSDavid du Colombier if(DEBUG){
16177dd7cddfSDavid du Colombier oui = (oui & 0x3FF)<<6;
16187dd7cddfSDavid du Colombier oui |= miir(ctlr, k, 3)>>10;
16197dd7cddfSDavid du Colombier miir(ctlr, k, 1);
16207dd7cddfSDavid du Colombier debug("phy%d: index %d oui %uX reg1 %uX\n",
16217dd7cddfSDavid du Colombier x, k, oui, miir(ctlr, k, 1));
16227dd7cddfSDavid du Colombier USED(oui);
16237dd7cddfSDavid du Colombier }
16247dd7cddfSDavid du Colombier ctlr->phy[x] = k;
16257dd7cddfSDavid du Colombier }
16267dd7cddfSDavid du Colombier }
16277dd7cddfSDavid du Colombier
16287dd7cddfSDavid du Colombier ctlr->fd = 0;
16297dd7cddfSDavid du Colombier ctlr->medium = -1;
16307dd7cddfSDavid du Colombier
16317dd7cddfSDavid du Colombier return 0;
16327dd7cddfSDavid du Colombier }
16337dd7cddfSDavid du Colombier
16347dd7cddfSDavid du Colombier static void
dec2114xpci(void)16357dd7cddfSDavid du Colombier dec2114xpci(void)
16367dd7cddfSDavid du Colombier {
16377dd7cddfSDavid du Colombier Ctlr *ctlr;
16387dd7cddfSDavid du Colombier Pcidev *p;
16397dd7cddfSDavid du Colombier int x;
16407dd7cddfSDavid du Colombier
16417dd7cddfSDavid du Colombier p = nil;
164259cc4ca5SDavid du Colombier while(p = pcimatch(p, 0, 0)){
164359cc4ca5SDavid du Colombier if(p->ccrb != 0x02 || p->ccru != 0)
164459cc4ca5SDavid du Colombier continue;
164559cc4ca5SDavid du Colombier switch((p->did<<16)|p->vid){
16467dd7cddfSDavid du Colombier default:
16477dd7cddfSDavid du Colombier continue;
16487dd7cddfSDavid du Colombier
164959cc4ca5SDavid du Colombier case Tulip3: /* 21143 */
16507dd7cddfSDavid du Colombier /*
16517dd7cddfSDavid du Colombier * Exit sleep mode.
16527dd7cddfSDavid du Colombier */
16537dd7cddfSDavid du Colombier x = pcicfgr32(p, 0x40);
1654f43e6a25SDavid du Colombier x &= ~0xC0000000;
16557dd7cddfSDavid du Colombier pcicfgw32(p, 0x40, x);
16567dd7cddfSDavid du Colombier /*FALLTHROUGH*/
16577dd7cddfSDavid du Colombier
1658d9306527SDavid du Colombier case Tulip0: /* 21140 */
1659f43e6a25SDavid du Colombier case Tulip1: /* 21041 */
1660c957ad6aSDavid du Colombier case Pnic: /* PNIC */
166159cc4ca5SDavid du Colombier case Pnic2: /* PNIC-II */
1662d9306527SDavid du Colombier case CentaurP: /* ADMtek */
1663b4b9fc2fSDavid du Colombier case CentaurPcb: /* ADMtek CardBus */
16647dd7cddfSDavid du Colombier break;
16657dd7cddfSDavid du Colombier }
16667dd7cddfSDavid du Colombier
16677dd7cddfSDavid du Colombier /*
16687dd7cddfSDavid du Colombier * bar[0] is the I/O port register address and
16697dd7cddfSDavid du Colombier * bar[1] is the memory-mapped register address.
16707dd7cddfSDavid du Colombier */
16717dd7cddfSDavid du Colombier ctlr = malloc(sizeof(Ctlr));
1672aa72973aSDavid du Colombier if(ctlr == nil)
1673aa72973aSDavid du Colombier error(Enomem);
16747dd7cddfSDavid du Colombier ctlr->port = p->mem[0].bar & ~0x01;
16757dd7cddfSDavid du Colombier ctlr->pcidev = p;
167659cc4ca5SDavid du Colombier ctlr->id = (p->did<<16)|p->vid;
16777dd7cddfSDavid du Colombier
16787dd7cddfSDavid du Colombier if(ioalloc(ctlr->port, p->mem[0].size, 0, "dec2114x") < 0){
167959cc4ca5SDavid du Colombier print("dec2114x: port 0x%uX in use\n", ctlr->port);
16807dd7cddfSDavid du Colombier free(ctlr);
16817dd7cddfSDavid du Colombier continue;
16827dd7cddfSDavid du Colombier }
16837dd7cddfSDavid du Colombier
16847dd7cddfSDavid du Colombier /*
16857dd7cddfSDavid du Colombier * Some cards (e.g. ANA-6910FX) seem to need the Ps bit
16867dd7cddfSDavid du Colombier * set or they don't always work right after a hardware
16877dd7cddfSDavid du Colombier * reset.
16887dd7cddfSDavid du Colombier */
16897dd7cddfSDavid du Colombier csr32w(ctlr, 6, Mbo|Ps);
16907dd7cddfSDavid du Colombier softreset(ctlr);
16917dd7cddfSDavid du Colombier
16927dd7cddfSDavid du Colombier if(srom(ctlr)){
169359cc4ca5SDavid du Colombier iofree(ctlr->port);
16947dd7cddfSDavid du Colombier free(ctlr);
169559cc4ca5SDavid du Colombier continue;
169659cc4ca5SDavid du Colombier }
169759cc4ca5SDavid du Colombier
169859cc4ca5SDavid du Colombier switch(ctlr->id){
169959cc4ca5SDavid du Colombier default:
170059cc4ca5SDavid du Colombier break;
170159cc4ca5SDavid du Colombier case Pnic: /* PNIC */
170259cc4ca5SDavid du Colombier /*
170359cc4ca5SDavid du Colombier * Turn off the jabber timer.
170459cc4ca5SDavid du Colombier */
170559cc4ca5SDavid du Colombier csr32w(ctlr, 15, 0x00000001);
17067dd7cddfSDavid du Colombier break;
1707d9306527SDavid du Colombier case CentaurP:
1708b4b9fc2fSDavid du Colombier case CentaurPcb:
1709d9306527SDavid du Colombier /*
1710d9306527SDavid du Colombier * Nice - the register offsets change from *8 to *4
1711d9306527SDavid du Colombier * for CSR16 and up...
1712d9306527SDavid du Colombier * CSR25/26 give the MAC address read from the SROM.
1713d9306527SDavid du Colombier * Don't really need to use this other than as a check,
1714d9306527SDavid du Colombier * the SROM will be read in anyway so the value there
1715d9306527SDavid du Colombier * can be used directly.
1716d9306527SDavid du Colombier */
1717d9306527SDavid du Colombier debug("csr25 %8.8luX csr26 %8.8luX\n",
1718d9306527SDavid du Colombier inl(ctlr->port+0xA4), inl(ctlr->port+0xA8));
1719d9306527SDavid du Colombier debug("phyidr1 %4.4luX phyidr2 %4.4luX\n",
1720d9306527SDavid du Colombier inl(ctlr->port+0xBC), inl(ctlr->port+0xC0));
1721d9306527SDavid du Colombier break;
17227dd7cddfSDavid du Colombier }
17237dd7cddfSDavid du Colombier
17247dd7cddfSDavid du Colombier if(ctlrhead != nil)
17257dd7cddfSDavid du Colombier ctlrtail->next = ctlr;
17267dd7cddfSDavid du Colombier else
17277dd7cddfSDavid du Colombier ctlrhead = ctlr;
17287dd7cddfSDavid du Colombier ctlrtail = ctlr;
17297dd7cddfSDavid du Colombier }
17307dd7cddfSDavid du Colombier }
17317dd7cddfSDavid du Colombier
17327dd7cddfSDavid du Colombier static int
reset(Ether * ether)17337dd7cddfSDavid du Colombier reset(Ether* ether)
17347dd7cddfSDavid du Colombier {
17357dd7cddfSDavid du Colombier Ctlr *ctlr;
17367dd7cddfSDavid du Colombier int i, x;
17377dd7cddfSDavid du Colombier uchar ea[Eaddrlen];
17387dd7cddfSDavid du Colombier static int scandone;
17397dd7cddfSDavid du Colombier
17407dd7cddfSDavid du Colombier if(scandone == 0){
17417dd7cddfSDavid du Colombier dec2114xpci();
17427dd7cddfSDavid du Colombier scandone = 1;
17437dd7cddfSDavid du Colombier }
17447dd7cddfSDavid du Colombier
17457dd7cddfSDavid du Colombier /*
17467dd7cddfSDavid du Colombier * Any adapter matches if no ether->port is supplied,
17477dd7cddfSDavid du Colombier * otherwise the ports must match.
17487dd7cddfSDavid du Colombier */
17497dd7cddfSDavid du Colombier for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
17507dd7cddfSDavid du Colombier if(ctlr->active)
17517dd7cddfSDavid du Colombier continue;
17527dd7cddfSDavid du Colombier if(ether->port == 0 || ether->port == ctlr->port){
17537dd7cddfSDavid du Colombier ctlr->active = 1;
17547dd7cddfSDavid du Colombier break;
17557dd7cddfSDavid du Colombier }
17567dd7cddfSDavid du Colombier }
17577dd7cddfSDavid du Colombier if(ctlr == nil)
17587dd7cddfSDavid du Colombier return -1;
17597dd7cddfSDavid du Colombier
17607dd7cddfSDavid du Colombier ether->ctlr = ctlr;
17617dd7cddfSDavid du Colombier ether->port = ctlr->port;
17627dd7cddfSDavid du Colombier ether->irq = ctlr->pcidev->intl;
17637dd7cddfSDavid du Colombier ether->tbdf = ctlr->pcidev->tbdf;
17647dd7cddfSDavid du Colombier
17657dd7cddfSDavid du Colombier /*
17667dd7cddfSDavid du Colombier * Check if the adapter's station address is to be overridden.
17677dd7cddfSDavid du Colombier * If not, read it from the EEPROM and set in ether->ea prior to
17687dd7cddfSDavid du Colombier * loading the station address in the hardware.
17697dd7cddfSDavid du Colombier */
17707dd7cddfSDavid du Colombier memset(ea, 0, Eaddrlen);
17717dd7cddfSDavid du Colombier if(memcmp(ea, ether->ea, Eaddrlen) == 0)
17727dd7cddfSDavid du Colombier memmove(ether->ea, ctlr->sromea, Eaddrlen);
17737dd7cddfSDavid du Colombier
17747dd7cddfSDavid du Colombier /*
17757dd7cddfSDavid du Colombier * Look for a medium override in case there's no autonegotiation
17767dd7cddfSDavid du Colombier * (no MII) or the autonegotiation fails.
17777dd7cddfSDavid du Colombier */
17787dd7cddfSDavid du Colombier for(i = 0; i < ether->nopt; i++){
17797dd7cddfSDavid du Colombier if(cistrcmp(ether->opt[i], "FD") == 0){
17807dd7cddfSDavid du Colombier ctlr->fd = 1;
17817dd7cddfSDavid du Colombier continue;
17827dd7cddfSDavid du Colombier }
17837dd7cddfSDavid du Colombier for(x = 0; x < nelem(mediatable); x++){
17847dd7cddfSDavid du Colombier debug("compare <%s> <%s>\n", mediatable[x],
17857dd7cddfSDavid du Colombier ether->opt[i]);
17867dd7cddfSDavid du Colombier if(cistrcmp(mediatable[x], ether->opt[i]))
17877dd7cddfSDavid du Colombier continue;
17887dd7cddfSDavid du Colombier ctlr->medium = x;
17897dd7cddfSDavid du Colombier
17907dd7cddfSDavid du Colombier switch(ctlr->medium){
17917dd7cddfSDavid du Colombier default:
17927dd7cddfSDavid du Colombier ctlr->fd = 0;
17937dd7cddfSDavid du Colombier break;
17947dd7cddfSDavid du Colombier
17957dd7cddfSDavid du Colombier case 0x04: /* 10BASE-TFD */
17967dd7cddfSDavid du Colombier case 0x05: /* 100BASE-TXFD */
17977dd7cddfSDavid du Colombier case 0x08: /* 100BASE-FXFD */
17987dd7cddfSDavid du Colombier ctlr->fd = 1;
17997dd7cddfSDavid du Colombier break;
18007dd7cddfSDavid du Colombier }
18017dd7cddfSDavid du Colombier break;
18027dd7cddfSDavid du Colombier }
18037dd7cddfSDavid du Colombier }
18047dd7cddfSDavid du Colombier
18057dd7cddfSDavid du Colombier ether->mbps = media(ether, 1);
18067dd7cddfSDavid du Colombier
18077dd7cddfSDavid du Colombier /*
18087dd7cddfSDavid du Colombier * Initialise descriptor rings, ethernet address.
18097dd7cddfSDavid du Colombier */
18107dd7cddfSDavid du Colombier ctlr->nrdr = Nrde;
18117dd7cddfSDavid du Colombier ctlr->ntdr = Ntde;
18127dd7cddfSDavid du Colombier pcisetbme(ctlr->pcidev);
18137dd7cddfSDavid du Colombier ctlrinit(ether);
18147dd7cddfSDavid du Colombier
18157dd7cddfSDavid du Colombier /*
18167dd7cddfSDavid du Colombier * Linkage to the generic ethernet driver.
18177dd7cddfSDavid du Colombier */
18187dd7cddfSDavid du Colombier ether->attach = attach;
18197dd7cddfSDavid du Colombier ether->transmit = transmit;
18207dd7cddfSDavid du Colombier ether->interrupt = interrupt;
18217dd7cddfSDavid du Colombier ether->ifstat = ifstat;
18227dd7cddfSDavid du Colombier
18237dd7cddfSDavid du Colombier ether->arg = ether;
18240809e9a7SDavid du Colombier ether->shutdown = shutdown;
18250809e9a7SDavid du Colombier ether->multicast = multicast;
18267dd7cddfSDavid du Colombier ether->promiscuous = promiscuous;
18277dd7cddfSDavid du Colombier
18287dd7cddfSDavid du Colombier return 0;
18297dd7cddfSDavid du Colombier }
18307dd7cddfSDavid du Colombier
18317dd7cddfSDavid du Colombier void
ether2114xlink(void)18327dd7cddfSDavid du Colombier ether2114xlink(void)
18337dd7cddfSDavid du Colombier {
18347dd7cddfSDavid du Colombier addethercard("2114x", reset);
1835b4b9fc2fSDavid du Colombier addethercard("21140", reset);
18367dd7cddfSDavid du Colombier }
1837