1 /* $NetBSD: if_le.c,v 1.4 2001/11/08 21:41:42 scw Exp $ */ 2 3 /* 4 * Copyright (c) 1995 Theo de Raadt 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed under OpenBSD by 17 * Theo de Raadt for Willowglen Singapore. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Copyright (c) 1993 Adam Glass 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by Adam Glass. 47 * 4. The name of the Author may not be used to endorse or promote products 48 * derived from this software without specific prior written permission. 49 * 50 * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND 51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 */ 62 63 #include <sys/param.h> 64 #include <sys/types.h> 65 66 #include <netinet/in.h> 67 #include <netinet/in_systm.h> 68 69 #include <machine/prom.h> 70 71 #include <lib/libkern/libkern.h> 72 #include <lib/libsa/stand.h> 73 #include <lib/libsa/net.h> 74 75 #include "libsa.h" 76 #include "netif.h" 77 #include "config.h" 78 #include "dev_net.h" 79 80 #include "if_lereg.h" 81 82 int le_debug = 0; 83 84 void le_end __P((struct netif *)); 85 void le_error __P((struct netif *, char *, volatile struct lereg1 *)); 86 int le_get __P((struct iodesc *, void *, size_t, time_t)); 87 void le_init __P((struct iodesc *, void *)); 88 int le_match __P((struct netif *, void *)); 89 int le_poll __P((struct iodesc *, void *, int)); 90 int le_probe __P((struct netif *, void *)); 91 int le_put __P((struct iodesc *, void *, size_t)); 92 void le_reset __P((struct netif *, u_char *)); 93 94 struct netif_stats le_stats; 95 96 struct netif_dif le0_dif = { 97 0, /* unit */ 98 1, /* nsel */ 99 &le_stats, 100 0, 101 0, 102 }; 103 104 struct netif_driver le_driver = { 105 "le", /* netif_bname */ 106 le_match, /* match */ 107 le_probe, /* probe */ 108 le_init, /* init */ 109 le_get, /* get */ 110 le_put, /* put */ 111 le_end, /* end */ 112 &le0_dif, /* netif_ifs */ 113 1, /* netif_nifs */ 114 }; 115 116 struct le_configuration { 117 unsigned int phys_addr; 118 int used; 119 } le_config[] = { 120 { LANCE_REG_ADDR, 0 } 121 }; 122 123 int nle_config = sizeof(le_config) / (sizeof(le_config[0])); 124 125 struct { 126 struct lereg1 *sc_r1; /* LANCE registers */ 127 struct lereg2 *sc_r2; /* RAM */ 128 int next_rmd; 129 int next_tmd; 130 } le_softc; 131 132 int 133 le_match(nif, machdep_hint) 134 struct netif *nif; 135 void *machdep_hint; 136 { 137 char *name; 138 int i, val = 0; 139 140 if (bugargs.cputyp != CPU_147) 141 return (0); 142 name = machdep_hint; 143 if (name && !memcmp(le_driver.netif_bname, name, 2)) 144 val += 10; 145 for (i = 0; i < nle_config; i++) { 146 if (le_config[i].used) 147 continue; 148 if (le_debug) 149 printf("le%d: le_match --> %d\n", i, val + 1); 150 le_config[i].used++; 151 return val + 1; 152 } 153 if (le_debug) 154 printf("le%d: le_match --> 0\n", i); 155 return 0; 156 } 157 158 int 159 le_probe(nif, machdep_hint) 160 struct netif *nif; 161 void *machdep_hint; 162 { 163 164 /* the set unit is the current unit */ 165 if (le_debug) 166 printf("le%d: le_probe called\n", nif->nif_unit); 167 168 if (bugargs.cputyp == CPU_147) 169 return 0; 170 return 1; 171 } 172 173 void 174 le_error(nif, str, ler1) 175 struct netif *nif; 176 char *str; 177 volatile struct lereg1 *ler1; 178 { 179 /* ler1->ler1_rap = LE_CSRO done in caller */ 180 if (ler1->ler1_rdp & LE_C0_BABL) 181 panic("le%d: been babbling, found by '%s'\n", nif->nif_unit, str); 182 if (ler1->ler1_rdp & LE_C0_CERR) { 183 le_stats.collision_error++; 184 ler1->ler1_rdp = LE_C0_CERR; 185 } 186 if (ler1->ler1_rdp & LE_C0_MISS) { 187 le_stats.missed++; 188 ler1->ler1_rdp = LE_C0_MISS; 189 } 190 if (ler1->ler1_rdp & LE_C0_MERR) { 191 printf("le%d: memory error in '%s'\n", nif->nif_unit, str); 192 panic("memory error"); 193 } 194 } 195 196 void 197 le_reset(nif, myea) 198 struct netif *nif; 199 u_char *myea; 200 { 201 struct lereg1 *ler1 = le_softc.sc_r1; 202 struct lereg2 *ler2 = le_softc.sc_r2; 203 unsigned int a; 204 int timo = 100000, stat = 0, i; 205 206 if (le_debug) 207 printf("le%d: le_reset called\n", nif->nif_unit); 208 ler1->ler1_rap = LE_CSR0; 209 ler1->ler1_rdp = LE_C0_STOP; /* do nothing until we are finished */ 210 211 memset(ler2, 0, sizeof(*ler2)); 212 213 ler2->ler2_mode = LE_MODE_NORMAL; 214 ler2->ler2_padr[0] = myea[1]; 215 ler2->ler2_padr[1] = myea[0]; 216 ler2->ler2_padr[2] = myea[3]; 217 ler2->ler2_padr[3] = myea[2]; 218 ler2->ler2_padr[4] = myea[5]; 219 ler2->ler2_padr[5] = myea[4]; 220 221 222 ler2->ler2_ladrf0 = 0; 223 ler2->ler2_ladrf1 = 0; 224 225 a = (u_int) ler2->ler2_rmd; 226 ler2->ler2_rlen = LE_RLEN | (a >> 16); 227 ler2->ler2_rdra = a & LE_ADDR_LOW_MASK; 228 229 a = (u_int) ler2->ler2_tmd; 230 ler2->ler2_tlen = LE_TLEN | (a >> 16); 231 ler2->ler2_tdra = a & LE_ADDR_LOW_MASK; 232 233 ler1->ler1_rap = LE_CSR1; 234 a = (u_int) ler2; 235 ler1->ler1_rdp = a & LE_ADDR_LOW_MASK; 236 ler1->ler1_rap = LE_CSR2; 237 ler1->ler1_rdp = a >> 16; 238 239 for (i = 0; i < LERBUF; i++) { 240 a = (u_int) & ler2->ler2_rbuf[i]; 241 ler2->ler2_rmd[i].rmd0 = a & LE_ADDR_LOW_MASK; 242 ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN; 243 ler2->ler2_rmd[i].rmd1_hadr = a >> 16; 244 ler2->ler2_rmd[i].rmd2 = -LEMTU; 245 ler2->ler2_rmd[i].rmd3 = 0; 246 } 247 for (i = 0; i < LETBUF; i++) { 248 a = (u_int) & ler2->ler2_tbuf[i]; 249 ler2->ler2_tmd[i].tmd0 = a & LE_ADDR_LOW_MASK; 250 ler2->ler2_tmd[i].tmd1_bits = 0; 251 ler2->ler2_tmd[i].tmd1_hadr = a >> 16; 252 ler2->ler2_tmd[i].tmd2 = 0; 253 ler2->ler2_tmd[i].tmd3 = 0; 254 } 255 256 ler1->ler1_rap = LE_CSR3; 257 ler1->ler1_rdp = LE_C3_BSWP; 258 259 ler1->ler1_rap = LE_CSR0; 260 ler1->ler1_rdp = LE_C0_INIT; 261 do { 262 if (--timo == 0) { 263 printf("le%d: init timeout, stat = 0x%x\n", 264 nif->nif_unit, stat); 265 break; 266 } 267 stat = ler1->ler1_rdp; 268 } while ((stat & LE_C0_IDON) == 0); 269 270 ler1->ler1_rdp = LE_C0_IDON; 271 le_softc.next_rmd = 0; 272 le_softc.next_tmd = 0; 273 ler1->ler1_rap = LE_CSR0; 274 ler1->ler1_rdp = LE_C0_STRT; 275 } 276 277 int 278 le_poll(desc, pkt, len) 279 struct iodesc *desc; 280 void *pkt; 281 int len; 282 { 283 struct lereg1 *ler1 = le_softc.sc_r1; 284 struct lereg2 *ler2 = le_softc.sc_r2; 285 unsigned int a; 286 int length; 287 struct lermd *rmd; 288 289 290 ler1->ler1_rap = LE_CSR0; 291 if ((ler1->ler1_rdp & LE_C0_RINT) != 0) 292 ler1->ler1_rdp = LE_C0_RINT; 293 rmd = &ler2->ler2_rmd[le_softc.next_rmd]; 294 if (rmd->rmd1_bits & LE_R1_OWN) { 295 return (0); 296 } 297 if (ler1->ler1_rdp & LE_C0_ERR) 298 le_error(desc->io_netif, "le_poll", ler1); 299 if (rmd->rmd1_bits & LE_R1_ERR) { 300 printf("le%d_poll: rmd status 0x%x\n", desc->io_netif->nif_unit, 301 rmd->rmd1_bits); 302 length = 0; 303 goto cleanup; 304 } 305 if ((rmd->rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != (LE_R1_STP | LE_R1_ENP)) 306 panic("le_poll: chained packet\n"); 307 308 length = rmd->rmd3; 309 if (length >= LEMTU) { 310 length = 0; 311 panic("csr0 when bad things happen: %x\n", ler1->ler1_rdp); 312 goto cleanup; 313 } 314 if (!length) 315 goto cleanup; 316 length -= 4; 317 if (length > 0) { 318 319 /* 320 * if buffer is smaller than the packet truncate it. 321 * (is this wise?) 322 */ 323 if (length > len) 324 length = len; 325 326 memcpy(pkt, (void *)&ler2->ler2_rbuf[le_softc.next_rmd], 327 length); 328 } 329 cleanup: 330 a = (u_int) & ler2->ler2_rbuf[le_softc.next_rmd]; 331 rmd->rmd0 = a & LE_ADDR_LOW_MASK; 332 rmd->rmd1_hadr = a >> 16; 333 rmd->rmd2 = -LEMTU; 334 le_softc.next_rmd = 335 (le_softc.next_rmd == (LERBUF - 1)) ? 0 : (le_softc.next_rmd + 1); 336 rmd->rmd1_bits = LE_R1_OWN; 337 return length; 338 } 339 340 int 341 le_put(desc, pkt, len) 342 struct iodesc *desc; 343 void *pkt; 344 size_t len; 345 { 346 volatile struct lereg1 *ler1 = le_softc.sc_r1; 347 volatile struct lereg2 *ler2 = le_softc.sc_r2; 348 volatile struct letmd *tmd; 349 int timo = 100000, stat = 0; 350 unsigned int a; 351 352 ler1->ler1_rap = LE_CSR0; 353 if (ler1->ler1_rdp & LE_C0_ERR) 354 le_error(desc->io_netif, "le_put(way before xmit)", ler1); 355 tmd = &ler2->ler2_tmd[le_softc.next_tmd]; 356 while (tmd->tmd1_bits & LE_T1_OWN) { 357 printf("le%d: output buffer busy\n", desc->io_netif->nif_unit); 358 } 359 memcpy((void *)ler2->ler2_tbuf[le_softc.next_tmd], pkt, len); 360 if (len < 64) 361 tmd->tmd2 = -64; 362 else 363 tmd->tmd2 = -len; 364 tmd->tmd3 = 0; 365 if (ler1->ler1_rdp & LE_C0_ERR) 366 le_error(desc->io_netif, "le_put(before xmit)", ler1); 367 tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP | LE_T1_OWN; 368 a = (u_int) & ler2->ler2_tbuf[le_softc.next_tmd]; 369 tmd->tmd0 = a & LE_ADDR_LOW_MASK; 370 tmd->tmd1_hadr = a >> 16; 371 ler1->ler1_rdp = LE_C0_TDMD; 372 if (ler1->ler1_rdp & LE_C0_ERR) 373 le_error(desc->io_netif, "le_put(after xmit)", ler1); 374 do { 375 if (--timo == 0) { 376 printf("le%d: transmit timeout, stat = 0x%x\n", 377 desc->io_netif->nif_unit, stat); 378 if (ler1->ler1_rdp & LE_C0_ERR) 379 le_error(desc->io_netif, "le_put(timeout)", ler1); 380 break; 381 } 382 stat = ler1->ler1_rdp; 383 } while ((stat & LE_C0_TINT) == 0); 384 ler1->ler1_rdp = LE_C0_TINT; 385 if (ler1->ler1_rdp & LE_C0_ERR) { 386 if ((ler1->ler1_rdp & (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS | 387 LE_C0_MERR)) != 388 LE_C0_CERR) 389 printf("le_put: xmit error, buf %d\n", le_softc.next_tmd); 390 le_error(desc->io_netif, "le_put(xmit error)", ler1); 391 } 392 le_softc.next_tmd = 0; 393 /* (le_softc.next_tmd == (LETBUF - 1)) ? 0 : le_softc.next_tmd + 1;*/ 394 if (tmd->tmd1_bits & LE_T1_DEF) 395 le_stats.deferred++; 396 if (tmd->tmd1_bits & LE_T1_ONE) 397 le_stats.collisions++; 398 if (tmd->tmd1_bits & LE_T1_MORE) 399 le_stats.collisions += 2; 400 if (tmd->tmd1_bits & LE_T1_ERR) { 401 printf("le%d: transmit error, error = 0x%x\n", desc->io_netif->nif_unit, 402 tmd->tmd3); 403 return -1; 404 } 405 if (le_debug) { 406 printf("le%d: le_put() successful: sent %d\n", 407 desc->io_netif->nif_unit, len); 408 printf("le%d: le_put(): tmd1_bits: %x tmd3: %x\n", 409 desc->io_netif->nif_unit, 410 (unsigned int) tmd->tmd1_bits, 411 (unsigned int) tmd->tmd3); 412 } 413 return len; 414 } 415 416 int 417 le_get(desc, pkt, len, timeout) 418 struct iodesc *desc; 419 void *pkt; 420 size_t len; 421 time_t timeout; 422 { 423 time_t t; 424 int cc; 425 426 t = getsecs(); 427 cc = 0; 428 while (((getsecs() - t) < timeout) && !cc) { 429 cc = le_poll(desc, pkt, len); 430 } 431 return cc; 432 } 433 /* 434 * init le device. return 0 on failure, 1 if ok. 435 */ 436 void 437 le_init(desc, machdep_hint) 438 struct iodesc *desc; 439 void *machdep_hint; 440 { 441 u_long eram = 4*1024*1024; 442 struct netif *nif = desc->io_netif; 443 444 if (le_debug) 445 printf("le%d: le_init called\n", desc->io_netif->nif_unit); 446 machdep_common_ether(desc->myea); 447 memset(&le_softc, 0, sizeof(le_softc)); 448 le_softc.sc_r1 = 449 (struct lereg1 *) le_config[desc->io_netif->nif_unit].phys_addr; 450 le_softc.sc_r2 = (struct lereg2 *) (eram - (1024 * 1024)); 451 le_reset(desc->io_netif, desc->myea); 452 printf("device: %s%d attached to %s\n", nif->nif_driver->netif_bname, 453 nif->nif_unit, ether_sprintf(desc->myea)); 454 } 455 456 void 457 le_end(nif) 458 struct netif *nif; 459 { 460 struct lereg1 *ler1 = le_softc.sc_r1; 461 462 if (le_debug) 463 printf("le%d: le_end called\n", nif->nif_unit); 464 ler1->ler1_rap = LE_CSR0; 465 ler1->ler1_rdp = LE_C0_STOP; 466 } 467