1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc. 7 * 8 * %sccs.include.redist.c% 9 * 10 * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY 11 * 12 * @(#)if_en.c 7.6 (Berkeley) 12/17/92 13 */ 14 15 #include "en.h" 16 #include "rawether.h" 17 #include "bpfilter.h" 18 19 #if NEN > 0 20 21 /* 22 * Interlan Ethernet Communications Controller interface 23 */ 24 #include <sys/types.h> 25 #include <machine/fix_machine_type.h> 26 #include <machine/pte.h> 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/mbuf.h> 31 #include <sys/buf.h> 32 #include <sys/protosw.h> 33 #include <sys/socket.h> 34 #include <sys/ioctl.h> 35 #include <sys/errno.h> 36 #include <sys/time.h> 37 #include <sys/cdefs.h> 38 39 #include <net/if.h> 40 #include <net/netisr.h> 41 #include <net/route.h> 42 43 #ifdef INET 44 #include <netinet/in.h> 45 #include <netinet/in_systm.h> 46 #include <netinet/in_var.h> 47 #include <netinet/ip.h> 48 #include <netinet/if_ether.h> 49 #endif 50 51 #include <news3400/if/if_news.h> 52 #include <news3400/if/if_en.h> 53 54 #ifdef CPU_SINGLE 55 #include <news3400/hbdev/hbvar.h> 56 #define iop_device hb_device 57 #define iop_driver hb_driver 58 #define ii_unit hi_unit 59 #define ii_intr hi_intr 60 #define ii_alive hi_alive 61 #else 62 #include <news3400/iop/iopvar.h> 63 #endif 64 65 int enprobe(), enattach(), enrint(), enxint(); 66 struct mbuf *m_devget(); 67 68 #ifdef CPU_SINGLE 69 struct hb_device *eninfo[NEN]; 70 struct hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo }; 71 #else 72 struct iop_device *eninfo[NEN]; 73 struct iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo }; 74 #endif 75 76 #define ENUNIT(x) minor(x) 77 78 int eninit(),enioctl(),enreset(),enwatch(),enstart(); 79 int endebug = 0; 80 81 struct ether_addr { 82 u_char addr[6]; 83 }; 84 85 extern struct ifnet loif; 86 87 struct en_softc en_softc[NEN]; 88 89 #if NBPFILTER > 0 90 #include <net/bpf.h> 91 #endif 92 93 enprobe(ii) 94 struct iop_device *ii; 95 { 96 97 return (en_probe(ii)); 98 } 99 100 /* 101 * Interface exists: make available by filling in network interface 102 * record. System will initialize the interface when it is ready 103 * to accept packets. A STATUS command is done to get the ethernet 104 * address and other interesting data. 105 */ 106 enattach(ii) 107 register struct iop_device *ii; 108 { 109 register struct en_softc *es = &en_softc[ii->ii_unit]; 110 register struct ifnet *ifp = &es->es_if; 111 extern char *ether_sprintf(); 112 113 en_attach(ii->ii_unit); 114 printf("en%d: hardware address %s\n", 115 ii->ii_unit, ether_sprintf((u_char *)es->es_addr)); 116 ifp->if_unit = ii->ii_unit; 117 ifp->if_name = "en"; 118 ifp->if_mtu = ETHERMTU; 119 ifp->if_init = eninit; 120 ifp->if_ioctl = enioctl; 121 ifp->if_output = ether_output; 122 #ifdef NOTDEF /* KU:XXX if_reset is obsolete */ 123 ifp->if_reset = enreset; 124 #endif 125 ifp->if_start = enstart; 126 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 127 #if NBPFILTER > 0 128 bpfattach(&es->es_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 129 #endif 130 if_attach(ifp); 131 } 132 133 /* 134 * Reset of interface after IOP reset. 135 */ 136 enreset(unit) 137 int unit; 138 { 139 register struct iop_device *ii; 140 141 if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0) 142 return; 143 printf(" en%d", unit); 144 en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); 145 en_softc[unit].es_flags &= ~ENF_RUNNING; 146 eninit(unit); 147 } 148 149 /* 150 * Initialization of interface; clear recorded pending 151 * operations, and reinitialize IOP usage. 152 */ 153 eninit(unit) 154 int unit; 155 { 156 register struct en_softc *es = &en_softc[unit]; 157 register struct ifnet *ifp = &es->es_if; 158 int s; 159 160 /* not yet, if address still unknown */ 161 if (ifp->if_addrlist == (struct ifaddr *)0) 162 return; 163 if (es->es_flags & ENF_RUNNING) 164 return; 165 if ((ifp->if_flags & IFF_RUNNING) == 0) { 166 if (if_newsinit(&es->es_ifnews, 167 sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) { 168 printf("en%d: can't initialize\n", unit); 169 es->es_if.if_flags &= ~IFF_UP; 170 return; 171 } 172 ifp->if_watchdog = enwatch; 173 es->es_interval = ENWATCHINTERVAL; 174 ifp->if_timer = es->es_interval; 175 s = splimp(); 176 en_init(unit); 177 splx(s); 178 } 179 es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS; 180 es->es_flags |= ENF_RUNNING; 181 } 182 183 /* 184 * Start output on interface. 185 * Get another datagram to send off of the interface queue, 186 * and map it to the interface before starting the output. 187 */ 188 enstart(ifp) 189 register struct ifnet *ifp; 190 { 191 int unit = ifp->if_unit, len; 192 register struct en_softc *es = &en_softc[unit]; 193 register struct mbuf *m; 194 int s; 195 196 IF_DEQUEUE(&es->es_if.if_snd, m); 197 if (m == 0) 198 return(0); 199 #ifdef CPU_SINGLE 200 es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit); 201 #endif 202 len = if_wnewsput(&es->es_ifnews, m); 203 /* 204 * Ensure minimum packet length. 205 * This makes the safe assumtion that there are no virtual holes 206 * after the data. 207 * For security, it might be wise to zero out the added bytes, 208 * but we're mainly interested in speed at the moment. 209 */ 210 if (len - sizeof(struct ether_header) < ETHERMIN) 211 len = ETHERMIN + sizeof(struct ether_header); 212 s = splclock(); /* KU:XXX should be gone */ 213 en_start(unit, len); 214 es->es_if.if_flags |= IFF_OACTIVE; 215 (void) splx(s); /* KU:XXX */ 216 #if NBPFILTER > 0 217 /* 218 * If bpf is listening on this interface, let it 219 * see the packet before we commit it to the wire. 220 */ 221 if (es->es_bpf) { 222 #ifdef CPU_SINGLE 223 bpf_tap(es->es_bpf, es->es_ifnews.ifn_waddr, len); 224 #else 225 bpf_mtap(es->es_bpf, m); 226 #endif 227 } 228 #endif /* NBPFILTER > 0 */ 229 return(0); 230 } 231 232 /* 233 * Transmit done interrupt. 234 */ 235 _enxint(unit, error, collision) 236 int unit; 237 int error, collision; 238 { 239 register struct en_softc *es = &en_softc[unit]; 240 241 #ifdef notyet /* KU:XXX */ 242 intrcnt[INTR_ETHER0 + unit]++; 243 #endif 244 if ((es->es_if.if_flags & IFF_OACTIVE) == 0) { 245 printf("en%d: stray xmit interrupt\n", unit); 246 return; 247 } else { 248 es->es_if.if_flags &= ~IFF_OACTIVE; 249 es->es_if.if_opackets++; 250 } 251 if (error) { 252 #ifdef DEBUG 253 printf("_enxint: error (unit=%d)\n", unit); 254 #endif 255 es->es_if.if_oerrors++; 256 } 257 if (collision) { 258 #ifdef DEBUG 259 printf("_enxint: collision (unit=%d)\n", unit); 260 #endif 261 es->es_if.if_collisions++; 262 } 263 enstart(&es->es_if); 264 } 265 266 /* 267 * Ethernet interface receiver interrupt. 268 * If input error just drop packet. 269 * Otherwise purge input buffered data path and examine 270 * packet to determine type. If can't determine length 271 * from type, then have to drop packet. Othewise decapsulate 272 * packet based on type and pass to type specific higher-level 273 * input routine. 274 */ 275 _enrint(unit, len) 276 int unit; 277 register int len; 278 { 279 register struct en_softc *es = &en_softc[unit]; 280 register struct en_rheader *en; 281 struct mbuf *m; 282 int off, resid, s; 283 int type; 284 register struct ensw *esp; 285 extern struct mbuf *if_rnewsget(); 286 #if defined(mips) && defined(CPU_SINGLE) 287 int bxcopy(); 288 #endif 289 290 #ifdef notyet /* KU:XXX */ 291 intrcnt[INTR_ETHER0 + unit]++; 292 #endif 293 es->es_if.if_ipackets++; 294 if ((es->es_flags & ENF_RUNNING) == 0) 295 return; 296 en = (struct en_rheader *)(es->es_ifnews.ifn_raddr); 297 if (len < ETHERMIN || len > ETHERMTU) { 298 es->es_if.if_ierrors++; 299 return; 300 } 301 #if NBPFILTER > 0 302 /* 303 * Check if there's a bpf filter listening on this interface. 304 * If so, hand off the raw packet to enet. 305 */ 306 if (es->es_bpf) { 307 bpf_tap(es->es_bpf, es->es_ifnews.ifn_raddr, 308 len + sizeof(struct en_rheader)); 309 /* 310 * Note that the interface cannot be in promiscuous mode if 311 * there are no bpf listeners. And if we are in promiscuous 312 * mode, we have to check if this packet is really ours. 313 * 314 * XXX This test does not support multicasts. 315 */ 316 if ((es->es_if.if_flags & IFF_PROMISC) 317 && bcmp(en->enr_dhost, es->es_addr, 318 sizeof(en->enr_dhost)) != 0 319 && bcmp(en->enr_dhost, etherbroadcastaddr, 320 sizeof(en->enr_dhost)) != 0) 321 return; 322 } 323 #endif /* NBPFILTER > 0 */ 324 /* 325 * Deal with trailer protocol: if type is trailer type 326 * get true type from first 16-bit word past data. 327 * Remember that type was trailer by setting off. 328 */ 329 en->enr_type = ntohs((u_short)en->enr_type); 330 #define endataaddr(en, off, type) ((type)(((caddr_t)((en)+1)+(off)))) 331 if (en->enr_type >= ETHERTYPE_TRAIL && 332 en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 333 off = (en->enr_type - ETHERTYPE_TRAIL) * 512; 334 if (off >= ETHERMTU) 335 return; 336 en->enr_type = ntohs(*endataaddr(en, off, u_short *)); 337 resid = ntohs(*(endataaddr(en, off+2, u_short *))); 338 if (off + resid > len) 339 return; 340 len = off + resid; 341 } else 342 off = 0; 343 /* 344 * Pull packet off interface. Off is nonzero if packet 345 * has trailing header; m_devget will then force this header 346 * information to be at the front, but we still have to drop 347 * the type and length which are at the front of any trailer data. 348 * KU:XXX really? 349 */ 350 type = en->enr_type; 351 #if defined(mips) && defined(CPU_SINGLE) 352 m = m_devget((char *)(en + 1), len, off, &es->es_if, bxcopy); 353 #else 354 m = m_devget((char *)(en + 1), len, off, &es->es_if, 0); 355 #endif 356 if (m == 0) 357 return; 358 ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m); 359 } 360 361 /* 362 * Watchdog routine, request statistics from board. 363 */ 364 enwatch(unit) 365 int unit; 366 { 367 register struct en_softc *es = &en_softc[unit]; 368 register struct ifnet *ifp = &es->es_if; 369 370 ifp->if_timer = es->es_interval; 371 } 372 373 /* 374 * Process an ioctl request. 375 */ 376 enioctl(ifp, cmd, data) 377 register struct ifnet *ifp; 378 int cmd; 379 caddr_t data; 380 { 381 register struct ifaddr *ifa = (struct ifaddr *)data; 382 register struct en_softc *es = &en_softc[ifp->if_unit]; 383 register struct ensw *esp; 384 register int family; 385 int s = splimp(), error = 0; 386 387 switch (cmd) { 388 389 case SIOCSIFADDR: 390 ifp->if_flags |= IFF_UP; 391 eninit(ifp->if_unit); 392 switch (ifa->ifa_addr->sa_family) { 393 #ifdef INET 394 case AF_INET: 395 ((struct arpcom *)ifp)->ac_ipaddr = 396 IA_SIN(ifa)->sin_addr; 397 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 398 break; 399 #endif 400 } 401 break; 402 403 case SIOCSIFFLAGS: 404 if ((ifp->if_flags & IFF_UP) == 0 && 405 es->es_flags & ENF_RUNNING) { 406 es->es_flags &= ~ENF_RUNNING; 407 } else if (ifp->if_flags & IFF_UP && 408 (es->es_flags & ENF_RUNNING) == 0) 409 eninit(ifp->if_unit); 410 #if NBPFILTER > 0 411 else if (ifp->if_flags & IFF_UP && 412 (ifp->if_flags & IFF_RUNNING) == 0) { 413 en_prom_mode(ifp->if_unit, 414 ifp->if_flags & IFF_PROMISC); 415 ifp->if_flags |= IFF_RUNNING; 416 } 417 #endif 418 break; 419 420 default: 421 error = EINVAL; 422 } 423 splx(s); 424 return (error); 425 } 426 427 /* 428 * set ethernet address for unit 429 */ 430 ensetaddr(physaddr, unit) 431 u_char *physaddr; 432 int unit; 433 { 434 register struct en_softc *es = &en_softc[unit]; 435 436 if (!(es->es_flags & ENF_RUNNING)) 437 return; 438 439 bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr); 440 es->es_flags &= ~ENF_RUNNING; 441 es->es_flags |= ENF_SETADDR; 442 eninit(unit); 443 } 444 445 /* 446 * Machine dependent functions 447 * 448 * en_probe(); 449 * en_attach(); 450 * en_init(); 451 * enxint(); 452 * enrint(); 453 * en_prom_mode() 454 */ 455 #ifdef CPU_SINGLE 456 #include <machine/cpu.h> 457 458 en_probe(hi) 459 struct hb_device *hi; 460 { 461 462 return (lance_probe(hi->hi_unit)); 463 } 464 465 en_attach(unit) 466 int unit; 467 { 468 register struct en_softc *es = &en_softc[unit]; 469 register u_char *p; 470 register int i; 471 extern lance_intr(); 472 473 #if !defined(news700) && !defined(mips) 474 register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr); 475 #endif 476 if (lance_open(unit) < 0) 477 printf("lance initialize error\n"); 478 lance_get_addr(unit, (caddr_t)es->es_addr); 479 } 480 481 en_init(unit) 482 int unit; 483 { 484 485 } 486 487 en_start(unit, len) 488 int unit; 489 int len; 490 { 491 492 lance_transmit(unit, len); 493 } 494 495 enxint(unit) 496 register int unit; 497 { 498 499 _enxint(unit, lance_xmit_error(unit), lance_collision(unit)); 500 } 501 502 enrint(unit) 503 register int unit; 504 { 505 register struct en_softc *es = &en_softc[unit]; 506 caddr_t get_recv_buffer(); 507 508 while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) { 509 _enrint(unit, 510 get_recv_length(unit) - sizeof(struct en_rheader)); 511 free_recv_buffer(unit); 512 } 513 } 514 515 en_prom_mode(unit, mode) 516 int unit, mode; 517 { 518 519 lance_prom_mode(unit, mode); 520 } 521 #endif /* CPU_SINGLE */ 522 523 #ifdef IPC_MRX 524 #include "../ipc/newsipc.h" 525 #include "../mrx/h/lancereg.h" 526 #include "../mrx/h/lance.h" 527 528 int port_enxmit[NEN]; 529 int port_enrecv[NEN]; 530 int port_enctrl[NEN]; 531 int port_enxmit_iop[NEN]; 532 int port_enrecv_iop[NEN]; 533 int port_enctrl_iop[NEN]; 534 535 en_probe(ii) 536 register struct iop_device *ii; 537 { 538 int unit = ii->ii_unit; 539 int lance_func, *reply; 540 char name[32]; 541 extern char *make_name(); 542 543 if (port_enrecv[unit] == 0) { 544 545 #define PT_CREATE(buf, name, unit, func) \ 546 port_create(make_name(buf, name, unit), func, unit) 547 #define OB_QUERY(buf, name, unit) \ 548 object_query(make_name(buf, name, unit)) 549 550 make_name(name, "@enrecvX", unit); 551 port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint); 552 port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint); 553 port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL); 554 /* use NULL action port */ 555 port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit); 556 port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit); 557 port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit); 558 } 559 if (port_enctrl_iop[unit] < 0) 560 goto bad; 561 lance_func = EN_START; 562 msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 563 sizeof(lance_func), 0); 564 msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 565 if (*reply < 0) 566 goto bad; 567 lance_func = EN_STOP; 568 msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 569 sizeof(lance_func), 0); 570 msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 571 return (1); 572 bad: 573 return (0); 574 } 575 576 en_attach(unit) 577 int unit; 578 { 579 register struct en_softc *es = &en_softc[unit]; 580 int lance_func; 581 struct ether_addr *ether_addr; 582 583 lance_func = EN_GETADDR; 584 msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func, 585 sizeof(lance_func), 0); 586 msg_recv(port_enctrl[unit], NULL, ðer_addr, NULL, 0); 587 bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr)); 588 msg_free(port_enctrl[unit]); 589 } 590 591 en_init(unit) 592 int unit; 593 { 594 register struct en_softc *es = &en_softc[unit]; 595 register int port; 596 struct lance_ctrl_req req; 597 int *reply; 598 599 req.lance_func = EN_SETXMITBUF; 600 mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr, 601 ETHERMTU + sizeof(struct en_rheader)); 602 msg_send(port_enctrl_iop[unit], port_enctrl[unit], 603 &req, sizeof(req), 0); 604 msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 605 606 req.lance_func = EN_START; 607 msg_send(port_enctrl_iop[unit], port_enctrl[unit], 608 &req, sizeof(req), 0); 609 msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0); 610 msg_free(port_enctrl[unit]); 611 612 msg_send(port_enrecv_iop[unit], port_enrecv[unit], 613 es->es_ifnews.ifn_raddr, 614 ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); 615 } 616 617 en_start(unit, len) 618 int unit; 619 int len; 620 { 621 622 msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0); 623 } 624 625 enxint(unit) 626 register int unit; 627 { 628 int *len; 629 struct en_softc *es = &en_softc[unit]; 630 631 if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) { 632 printf("stray enxint\n"); 633 return; 634 } 635 if (es->es_ifnews.ifn_mbuf) 636 m_freem(es->es_ifnews.ifn_mbuf); 637 _enxint(unit, *len < 0, *len & 0x10000); 638 } 639 640 enrint(unit) 641 int unit; 642 { 643 int len; 644 int *reply; 645 646 if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) { 647 printf("stray enrint\n"); 648 return; 649 } 650 len = *reply - sizeof(struct en_rheader); 651 msg_free(port_enrecv[unit]); 652 #ifdef mips 653 /* 654 * cache flush address must aligned long word boundary. 655 * so, add 3 for sanity. 656 */ 657 clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03, 658 len + sizeof (struct en_rheader) + 3); 659 #endif 660 _enrint(unit, len); 661 msg_send(port_enrecv_iop[unit], port_enrecv[unit], 662 en_softc[unit].es_ifnews.ifn_raddr, 663 ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT); 664 } 665 666 en_prom_mode(unit, mode) 667 int unit, mode; 668 { 669 static int port; 670 struct lance_ctrl_req req; 671 extern int port_enctrl_iop[]; 672 673 req.lance_func = EN_PROMMODE; 674 req.lance_mode = mode; 675 msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0); 676 } 677 #endif /* IPC_MRX */ 678 #endif /* NEN > 0 */ 679