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