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