1 /* 2 * SMSC LAN95XX 3 */ 4 5 #include <u.h> 6 #include <libc.h> 7 #include <fcall.h> 8 #include <thread.h> 9 #include "usb.h" 10 #include "usbfs.h" 11 #include "ether.h" 12 13 enum { 14 Doburst = 1, 15 Resettime = 1000, 16 E2pbusytime = 1000, 17 Afcdefault = 0xF830A1, 18 // Hsburst = 37, /* from original linux driver */ 19 Hsburst = 8, 20 Fsburst = 129, 21 Defbulkdly = 0x2000, 22 23 Ethp8021q = 0x8100, 24 MACoffset = 1, 25 PHYinternal = 1, 26 Rxerror = 0x8000, 27 Txfirst = 0x2000, 28 Txlast = 0x1000, 29 30 /* USB vendor requests */ 31 Writereg = 0xA0, 32 Readreg = 0xA1, 33 34 /* device registers */ 35 Intsts = 0x08, 36 Txcfg = 0x10, 37 Txon = 1<<2, 38 Hwcfg = 0x14, 39 Bir = 1<<12, 40 Rxdoff = 3<<9, 41 Mef = 1<<5, 42 Lrst = 1<<3, 43 Bce = 1<<1, 44 Pmctrl = 0x20, 45 Phyrst = 1<<4, 46 Ledgpio = 0x24, 47 Ledspd = 1<<24, 48 Ledlnk = 1<<20, 49 Ledfdx = 1<<16, 50 Afccfg = 0x2C, 51 E2pcmd = 0x30, 52 Busy = 1<<31, 53 Timeout = 1<<10, 54 Read = 0, 55 E2pdata = 0x34, 56 Burstcap = 0x38, 57 Intepctl = 0x68, 58 Phyint = 1<<15, 59 Bulkdelay = 0x6C, 60 Maccr = 0x100, 61 Mcpas = 1<<19, 62 Prms = 1<<18, 63 Hpfilt = 1<<13, 64 Txen = 1<<3, 65 Rxen = 1<<2, 66 Addrh = 0x104, 67 Addrl = 0x108, 68 Hashh = 0x10C, 69 Hashl = 0x110, 70 MIIaddr = 0x114, 71 MIIwrite= 1<<1, 72 MIIread = 0<<1, 73 MIIbusy = 1<<0, 74 MIIdata = 0x118, 75 Flow = 0x11C, 76 Vlan1 = 0x120, 77 Coecr = 0x130, 78 Txcoe = 1<<16, 79 Rxcoemd = 1<<1, 80 Rxcoe = 1<<0, 81 82 /* MII registers */ 83 Bmcr = 0, 84 Bmcrreset= 1<<15, 85 Speed100= 1<<13, 86 Anenable= 1<<12, 87 Anrestart= 1<<9, 88 Fulldpx = 1<<8, 89 Bmsr = 1, 90 Advertise = 4, 91 Adcsma = 0x0001, 92 Ad10h = 0x0020, 93 Ad10f = 0x0040, 94 Ad100h = 0x0080, 95 Ad100f = 0x0100, 96 Adpause = 0x0400, 97 Adpauseasym= 0x0800, 98 Adall = Ad10h|Ad10f|Ad100h|Ad100f, 99 Phyintsrc = 29, 100 Phyintmask = 30, 101 Anegcomp= 1<<6, 102 Linkdown= 1<<4, 103 }; 104 105 static int 106 wr(Dev *d, int reg, int val) 107 { 108 int ret; 109 110 ret = usbcmd(d, Rh2d|Rvendor|Rdev, Writereg, 0, reg, 111 (uchar*)&val, sizeof(val)); 112 if(ret < 0) 113 deprint(2, "%s: wr(%x, %x): %r", argv0, reg, val); 114 return ret; 115 } 116 117 static int 118 rr(Dev *d, int reg) 119 { 120 int ret, rval; 121 122 ret = usbcmd(d, Rd2h|Rvendor|Rdev, Readreg, 0, reg, 123 (uchar*)&rval, sizeof(rval)); 124 if(ret < 0){ 125 fprint(2, "%s: rr(%x): %r", argv0, reg); 126 return 0; 127 } 128 return rval; 129 } 130 131 static int 132 miird(Dev *d, int idx) 133 { 134 while(rr(d, MIIaddr) & MIIbusy) 135 ; 136 wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIread); 137 while(rr(d, MIIaddr) & MIIbusy) 138 ; 139 return rr(d, MIIdata); 140 } 141 142 static void 143 miiwr(Dev *d, int idx, int val) 144 { 145 while(rr(d, MIIaddr) & MIIbusy) 146 ; 147 wr(d, MIIdata, val); 148 wr(d, MIIaddr, PHYinternal<<11 | idx<<6 | MIIwrite); 149 while(rr(d, MIIaddr) & MIIbusy) 150 ; 151 } 152 153 static int 154 eepromr(Dev *d, int off, uchar *buf, int len) 155 { 156 int i, v; 157 158 for(i = 0; i < E2pbusytime; i++) 159 if((rr(d, E2pcmd) & Busy) == 0) 160 break; 161 if(i == E2pbusytime) 162 return -1; 163 for(i = 0; i < len; i++){ 164 wr(d, E2pcmd, Busy|Read|(i+off)); 165 while((v = rr(d, E2pcmd) & (Busy|Timeout)) == Busy) 166 ; 167 if(v & Timeout) 168 return -1; 169 buf[i] = rr(d, E2pdata); 170 } 171 return 0; 172 } 173 174 static void 175 phyinit(Dev *d) 176 { 177 int i; 178 179 miiwr(d, Bmcr, Bmcrreset|Anenable); 180 for(i = 0; i < Resettime/10; i++){ 181 if((miird(d, Bmcr) & Bmcrreset) == 0) 182 break; 183 sleep(10); 184 } 185 miiwr(d, Advertise, Adcsma|Adall|Adpause|Adpauseasym); 186 // miiwr(d, Advertise, Adcsma|Ad10f|Ad10h|Adpause|Adpauseasym); 187 miird(d, Phyintsrc); 188 miiwr(d, Phyintmask, Anegcomp|Linkdown); 189 miiwr(d, Bmcr, miird(d, Bmcr)|Anenable|Anrestart); 190 } 191 192 193 static int 194 doreset(Dev *d, int reg, int bit) 195 { 196 int i; 197 198 if(wr(d, reg, bit) < 0) 199 return -1; 200 for(i = 0; i < Resettime/10; i++){ 201 if((rr(d, reg) & bit) == 0) 202 return 1; 203 sleep(10); 204 } 205 return 0; 206 } 207 208 static int 209 getmac(Dev *d, uchar buf[]) 210 { 211 int i; 212 uchar ea[Eaddrlen]; 213 214 if(eepromr(d, MACoffset, ea, Eaddrlen) < 0) 215 return -1; 216 for(i = 0; i < Eaddrlen; i++) 217 if(ea[i] != 0 && ea[i] != 0xFF){ 218 memmove(buf, ea, Eaddrlen); 219 break; 220 } 221 return Eaddrlen; 222 } 223 224 static int 225 smscinit(Ether *ether) 226 { 227 Dev *d; 228 229 if(ether->cid != S95xx) 230 return -1; 231 d = ether->dev; 232 deprint(2, "%s: setting up SMSC95XX\n", argv0); 233 if(!doreset(d, Hwcfg, Lrst) || !doreset(d, Pmctrl, Phyrst)) 234 return -1; 235 if(getmac(d, ether->addr) < 0) 236 return -1; 237 wr(d, Addrl, GET4(ether->addr)); 238 wr(d, Addrh, GET2(ether->addr+4)); 239 if(Doburst){ 240 wr(d, Hwcfg, (rr(d,Hwcfg)&~Rxdoff)|Bir|Mef|Bce); 241 wr(d, Burstcap, Hsburst); 242 }else{ 243 wr(d, Hwcfg, (rr(d,Hwcfg)&~(Rxdoff|Mef|Bce))|Bir); 244 wr(d, Burstcap, 0); 245 } 246 wr(d, Bulkdelay, Defbulkdly); 247 wr(d, Intsts, ~0); 248 wr(d, Ledgpio, Ledspd|Ledlnk|Ledfdx); 249 wr(d, Flow, 0); 250 wr(d, Afccfg, Afcdefault); 251 wr(d, Vlan1, Ethp8021q); 252 wr(d, Coecr, rr(d,Coecr)&~(Txcoe|Rxcoe)); /* TODO could offload checksums? */ 253 254 wr(d, Hashh, 0); 255 wr(d, Hashl, 0); 256 wr(d, Maccr, rr(d,Maccr)&~(Prms|Mcpas|Hpfilt)); 257 258 phyinit(d); 259 260 wr(d, Intepctl, rr(d, Intepctl)|Phyint); 261 wr(d, Maccr, rr(d, Maccr)|Txen|Rxen); 262 wr(d, Txcfg, Txon); 263 264 return 0; 265 } 266 267 static long 268 smscbread(Ether *e, Buf *bp) 269 { 270 uint hd; 271 int n, m; 272 Buf *rbp; 273 274 rbp = e->aux; 275 if(rbp->ndata < 4){ 276 rbp->rp = rbp->data; 277 rbp->ndata = read(e->epin->dfd, rbp->rp, Doburst? Hsburst*512: 278 Maxpkt); 279 if(rbp->ndata < 0) 280 return -1; 281 } 282 if(rbp->ndata < 4){ 283 werrstr("short frame"); 284 fprint(2, "smsc short frame %d bytes\n", rbp->ndata); 285 return 0; 286 } 287 hd = GET4(rbp->rp); 288 n = hd >> 16; 289 m = (n + 4 + 3) & ~3; 290 if(n < 6 || m > rbp->ndata){ 291 werrstr("frame length"); 292 fprint(2, "smsc length error packet %d buf %d\n", n, rbp->ndata); 293 rbp->ndata = 0; 294 return 0; 295 } 296 if(hd & Rxerror){ 297 fprint(2, "smsc rx error %8.8ux\n", hd); 298 n = 0; 299 }else{ 300 bp->rp = bp->data + Hdrsize; 301 memmove(bp->rp, rbp->rp+4, n); 302 } 303 bp->ndata = n; 304 rbp->rp += m; 305 rbp->ndata -= m; 306 return n; 307 } 308 309 static long 310 smscbwrite(Ether *e, Buf *bp) 311 { 312 int n; 313 314 n = bp->ndata & 0x7FF; 315 bp->rp -= 8; 316 bp->ndata += 8; 317 PUT4(bp->rp, n | Txfirst | Txlast); 318 PUT4(bp->rp+4, n); 319 n = write(e->epout->dfd, bp->rp, bp->ndata); 320 return n; 321 } 322 323 static int 324 smscpromiscuous(Ether *e, int on) 325 { 326 USED(on, e); 327 #ifdef TODO /* copied from asix */ 328 int rxctl; 329 330 deprint(2, "%s: smscpromiscuous %d\n", argv0, on); 331 rxctl = getrxctl(e->dev); 332 if(on != 0) 333 rxctl |= Rxctlprom; 334 else 335 rxctl &= ~Rxctlprom; 336 return wr(e->dev, Cwrxctl, rxctl); 337 #endif 338 return -1; 339 } 340 341 static int 342 smscmulticast(Ether *e, uchar *addr, int on) 343 { 344 USED(addr, on, e); 345 #ifdef TODO /* needed for ipv6; copied from asix */ 346 int rxctl; 347 348 /* BUG: should write multicast filter */ 349 rxctl = getrxctl(e->dev); 350 if(e->nmcasts != 0) 351 rxctl |= Rxctlamall; 352 else 353 rxctl &= ~Rxctlamall; 354 deprint(2, "%s: smscmulticast %d\n", argv0, e->nmcasts); 355 return wr(e->dev, Cwrxctl, rxctl); 356 #endif 357 return -1; 358 } 359 360 static void 361 smscfree(Ether *ether) 362 { 363 free(ether->aux); 364 ether->aux = nil; 365 } 366 367 int 368 smscreset(Ether *ether) 369 { 370 Cinfo *ip; 371 Dev *dev; 372 373 dev = ether->dev; 374 for(ip = cinfo; ip->vid != 0; ip++) 375 if(ip->vid == dev->usb->vid && ip->did == dev->usb->did){ 376 ether->cid = ip->cid; 377 if(smscinit(ether) < 0){ 378 deprint(2, "%s: smsc init failed: %r\n", argv0); 379 return -1; 380 } 381 deprint(2, "%s: smsc reset done\n", argv0); 382 ether->name = "smsc"; 383 if(Doburst){ 384 ether->bufsize = Hsburst*512; 385 ether->aux = emallocz(sizeof(Buf) + 386 ether->bufsize - Maxpkt, 1); 387 }else{ 388 ether->bufsize = Maxpkt; 389 ether->aux = emallocz(sizeof(Buf), 1); 390 } 391 ether->free = smscfree; 392 ether->bread = smscbread; 393 ether->bwrite = smscbwrite; 394 ether->promiscuous = smscpromiscuous; 395 ether->multicast = smscmulticast; 396 ether->mbps = 100; /* BUG */ 397 return 0; 398 } 399 return -1; 400 } 401