1 /* 2 * 3C589 and 3C562. 3 * To do: 4 * check xcvr10Base2 still works (is GlobalReset necessary?). 5 */ 6 #include "u.h" 7 #include "lib.h" 8 #include "mem.h" 9 #include "dat.h" 10 #include "fns.h" 11 #include "io.h" 12 #include "error.h" 13 14 #include "etherif.h" 15 16 enum { /* all windows */ 17 CommandR = 0x000E, 18 IntStatusR = 0x000E, 19 }; 20 21 enum { /* Commands */ 22 GlobalReset = 0x0000, 23 SelectRegisterWindow = 0x0001, 24 RxReset = 0x0005, 25 TxReset = 0x000B, 26 AcknowledgeInterrupt = 0x000D, 27 }; 28 29 enum { /* IntStatus bits */ 30 commandInProgress = 0x1000, 31 }; 32 33 #define COMMAND(port, cmd, a) outs((port)+CommandR, ((cmd)<<11)|(a)) 34 #define STATUS(port) ins((port)+IntStatusR) 35 36 enum { /* Window 0 - setup */ 37 Wsetup = 0x0000, 38 /* registers */ 39 ManufacturerID = 0x0000, /* 3C5[08]*, 3C59[27] */ 40 ProductID = 0x0002, /* 3C5[08]*, 3C59[27] */ 41 ConfigControl = 0x0004, /* 3C5[08]*, 3C59[27] */ 42 AddressConfig = 0x0006, /* 3C5[08]*, 3C59[27] */ 43 ResourceConfig = 0x0008, /* 3C5[08]*, 3C59[27] */ 44 EepromCommand = 0x000A, 45 EepromData = 0x000C, 46 /* AddressConfig Bits */ 47 autoSelect9 = 0x0080, 48 xcvrMask9 = 0xC000, 49 /* ConfigControl bits */ 50 Ena = 0x0001, 51 base10TAvailable9 = 0x0200, 52 coaxAvailable9 = 0x1000, 53 auiAvailable9 = 0x2000, 54 /* EepromCommand bits */ 55 EepromReadRegister = 0x0080, 56 EepromBusy = 0x8000, 57 }; 58 59 enum { /* Window 1 - operating set */ 60 Wop = 0x0001, 61 }; 62 63 enum { /* Window 3 - FIFO management */ 64 Wfifo = 0x0003, 65 /* registers */ 66 InternalConfig = 0x0000, /* 3C509B, 3C589, 3C59[0257] */ 67 /* InternalConfig bits */ 68 xcvr10BaseT = 0x00000000, 69 xcvr10Base2 = 0x00300000, 70 }; 71 72 enum { /* Window 4 - diagnostic */ 73 Wdiagnostic = 0x0004, 74 /* registers */ 75 MediaStatus = 0x000A, 76 /* MediaStatus bits */ 77 linkBeatDetect = 0x0800, 78 }; 79 80 extern int elnk3reset(Ether*); 81 82 static char *tcmpcmcia[] = { 83 "3C589", /* 3COM 589[ABCD] */ 84 "3C562", /* 3COM 562 */ 85 "589E", /* 3COM Megahertz 589E */ 86 nil, 87 }; 88 89 static int 90 configASIC(Ether* ether, int port, int xcvr) 91 { 92 int x; 93 94 /* set Window 0 configuration registers */ 95 COMMAND(port, SelectRegisterWindow, Wsetup); 96 outs(port+ConfigControl, Ena); 97 98 /* IRQ must be 3 on 3C589/3C562 */ 99 outs(port + ResourceConfig, 0x3F00); 100 101 x = ins(port+AddressConfig) & ~xcvrMask9; 102 x |= (xcvr>>20)<<14; 103 outs(port+AddressConfig, x); 104 105 COMMAND(port, TxReset, 0); 106 while(STATUS(port) & commandInProgress) 107 ; 108 COMMAND(port, RxReset, 0); 109 while(STATUS(port) & commandInProgress) 110 ; 111 112 return elnk3reset(ether); 113 } 114 115 int 116 ether589reset(Ether* ether) 117 { 118 int i, t, slot; 119 char *type; 120 int port; 121 enum { WantAny, Want10BT, Want10B2 }; 122 int want; 123 uchar ea[6]; 124 char *p; 125 126 if(ether->irq == 0) 127 ether->irq = 10; 128 if(ether->port == 0) 129 ether->port = 0x240; 130 port = ether->port; 131 132 // if(ioalloc(port, 0x10, 0, "3C589") < 0) 133 // return -1; 134 135 type = nil; 136 slot = -1; 137 for(i = 0; tcmpcmcia[i] != nil; i++){ 138 type = tcmpcmcia[i]; 139 if(debug) print("try %s...", type); 140 if((slot = pcmspecial(type, ether)) >= 0) 141 break; 142 } 143 if(slot < 0){ 144 if(debug) print("none found\n"); 145 // iofree(port); 146 return -1; 147 } 148 149 /* 150 * Read Ethernet address from card memory 151 * on 3C562, but only if the user has not 152 * overridden it. 153 */ 154 memset(ea, 0, sizeof ea); 155 if(memcmp(ea, ether->ea, 6) == 0 && strcmp(type, "3C562") == 0) { 156 if(debug) 157 print("read 562..."); 158 if(pcmcistuple(slot, 0x88, -1, ea, 6) == 6) { 159 for(i = 0; i < 6; i += 2){ 160 t = ea[i]; 161 ea[i] = ea[i+1]; 162 ea[i+1] = t; 163 } 164 memmove(ether->ea, ea, 6); 165 if(debug) 166 print("ea %E", ea); 167 } 168 } 169 /* 170 * Allow user to specify desired media in plan9.ini 171 */ 172 want = WantAny; 173 for(i = 0; i < ether->nopt; i++){ 174 if(cistrncmp(ether->opt[i], "media=", 6) != 0) 175 continue; 176 p = ether->opt[i]+6; 177 if(cistrcmp(p, "10base2") == 0) 178 want = Want10B2; 179 else if(cistrcmp(p, "10baseT") == 0) 180 want = Want10BT; 181 } 182 183 /* try configuring as a 10BaseT */ 184 if(want==WantAny || want==Want10BT){ 185 if(configASIC(ether, port, xcvr10BaseT) < 0){ 186 pcmspecialclose(slot); 187 // iofree(port); 188 return -1; 189 } 190 delay(100); 191 COMMAND(port, SelectRegisterWindow, Wdiagnostic); 192 if((ins(port+MediaStatus)&linkBeatDetect) || want==Want10BT){ 193 COMMAND(port, SelectRegisterWindow, Wop); 194 print("#l%d: xcvr10BaseT %s\n", ether->ctlrno, type); 195 return 0; 196 } 197 } 198 199 /* try configuring as a 10base2 */ 200 if(want==WantAny || want==Want10B2){ 201 COMMAND(port, GlobalReset, 0); 202 if(configASIC(ether, port, xcvr10Base2) < 0){ 203 pcmspecialclose(slot); 204 // iofree(port); 205 return -1; 206 } 207 print("#l%d: xcvr10Base2 %s\n", ether->ctlrno, type); 208 return 0; 209 } 210 return -1; /* not reached */ 211 } 212