1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Computer Consoles Inc. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the University of California, Berkeley. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * @(#)if_enp.c 7.3 (Berkeley) 08/19/88 21 */ 22 23 #include "enp.h" 24 #if NENP > 0 25 /* 26 * CMC ENP-20 Ethernet Controller. 27 */ 28 #include "param.h" 29 #include "systm.h" 30 #include "mbuf.h" 31 #include "buf.h" 32 #include "protosw.h" 33 #include "socket.h" 34 #include "vmmac.h" 35 #include "ioctl.h" 36 #include "errno.h" 37 #include "vmparam.h" 38 #include "syslog.h" 39 #include "uio.h" 40 41 #include "../net/if.h" 42 #include "../net/netisr.h" 43 #include "../net/route.h" 44 #ifdef INET 45 #include "../netinet/in.h" 46 #include "../netinet/in_systm.h" 47 #include "../netinet/in_var.h" 48 #include "../netinet/ip.h" 49 #include "../netinet/ip_var.h" 50 #include "../netinet/if_ether.h" 51 #endif 52 #ifdef NS 53 #include "../netns/ns.h" 54 #include "../netns/ns_if.h" 55 #endif 56 57 #include "../tahoe/cpu.h" 58 #include "../tahoe/pte.h" 59 #include "../tahoe/mtpr.h" 60 61 #include "../tahoevba/vbavar.h" 62 #include "../tahoeif/if_enpreg.h" 63 64 #define ENPSTART 0xf02000 /* standard enp start addr */ 65 #define ENPUNIT(dev) (minor(dev)) /* for enp ram devices */ 66 /* macros for dealing with longs in i/o space */ 67 #define ENPGETLONG(a) ((((u_short *)(a))[0] << 16)|(((u_short *)(a))[1])) 68 #define ENPSETLONG(a,v) \ 69 { register u_short *wp = (u_short *)(a); \ 70 wp[0] = ((u_short *)&(v))[0]; wp[1] = ((u_short *)&(v))[1];} 71 72 int enpprobe(), enpattach(), enpintr(); 73 long enpstd[] = { 0xfff41000, 0xfff61000, 0 }; 74 struct vba_device *enpinfo[NENP]; 75 struct vba_driver enpdriver = 76 { enpprobe, 0, enpattach, 0, enpstd, "enp", enpinfo, "enp-20", 0 }; 77 78 int enpinit(), enpioctl(), enpreset(), enpoutput(), enpstart(); 79 struct mbuf *enpget(); 80 81 /* 82 * Ethernet software status per interface. 83 * 84 * Each interface is referenced by a network interface structure, 85 * es_if, which the routing code uses to locate the interface. 86 * This structure contains the output queue for the interface, its address, ... 87 */ 88 struct enp_softc { 89 struct arpcom es_ac; /* common ethernet structures */ 90 #define es_if es_ac.ac_if 91 #define es_addr es_ac.ac_enaddr 92 short es_ivec; /* interrupt vector */ 93 } enp_softc[NENP]; 94 extern struct ifnet loif; 95 96 enpprobe(reg, vi) 97 caddr_t reg; 98 struct vba_device *vi; 99 { 100 register br, cvec; /* must be r12, r11 */ 101 register struct enpdevice *addr = (struct enpdevice *)reg; 102 struct enp_softc *es = &enp_softc[vi->ui_unit]; 103 104 #ifdef lint 105 br = 0; cvec = br; br = cvec; 106 enpintr(0); 107 #endif 108 if (badaddr((caddr_t)addr, 2) || badaddr((caddr_t)&addr->enp_ram[0], 2)) 109 return (0); 110 es->es_ivec = --vi->ui_hd->vh_lastiv; 111 addr->enp_state = S_ENPRESET; /* reset by VERSAbus reset */ 112 br = 0x14, cvec = es->es_ivec; /* XXX */ 113 return (sizeof (struct enpdevice)); 114 } 115 116 /* 117 * Interface exists: make available by filling in network interface 118 * record. System will initialize the interface when it is ready 119 * to accept packets. 120 */ 121 enpattach(ui) 122 register struct vba_device *ui; 123 { 124 struct enp_softc *es = &enp_softc[ui->ui_unit]; 125 register struct ifnet *ifp = &es->es_if; 126 127 ifp->if_unit = ui->ui_unit; 128 ifp->if_name = "enp"; 129 ifp->if_mtu = ETHERMTU; 130 ifp->if_init = enpinit; 131 ifp->if_ioctl = enpioctl; 132 ifp->if_output = enoutput; 133 ifp->if_reset = enpreset; 134 ifp->if_start = enpstart; 135 ifp->if_flags = IFF_BROADCAST; 136 if_attach(ifp); 137 } 138 139 /* 140 * Reset of interface after "system" reset. 141 */ 142 enpreset(unit, vban) 143 int unit, vban; 144 { 145 register struct vba_device *ui; 146 147 if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 148 ui->ui_vbanum != vban) 149 return; 150 printf(" enp%d", unit); 151 enpinit(unit); 152 } 153 154 /* 155 * Initialization of interface; clear recorded pending operations. 156 */ 157 enpinit(unit) 158 int unit; 159 { 160 struct enp_softc *es = &enp_softc[unit]; 161 register struct vba_device *ui = enpinfo[unit]; 162 struct enpdevice *addr; 163 register struct ifnet *ifp = &es->es_if; 164 int s; 165 166 if (ifp->if_addrlist == (struct ifaddr *)0) 167 return; 168 if ((ifp->if_flags & IFF_RUNNING) == 0) { 169 addr = (struct enpdevice *)ui->ui_addr; 170 s = splimp(); 171 RESET_ENP(addr); 172 DELAY(200000); 173 es->es_if.if_flags |= IFF_RUNNING; 174 splx(s); 175 } 176 } 177 178 /* 179 * Ethernet interface interrupt. 180 */ 181 enpintr(unit) 182 int unit; 183 { 184 register struct enpdevice *addr; 185 register BCB *bcbp; 186 187 addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 188 #if ENP == 30 189 if (!IS_ENP_INTR(addr)) 190 return; 191 ACK_ENP_INTR(addr); 192 #endif 193 while ((bcbp = (BCB *)ringget((RING *)&addr->enp_tohost )) != 0) { 194 enpread(&enp_softc[unit], bcbp); 195 (void) ringput((RING *)&addr->enp_enpfree, bcbp); 196 } 197 } 198 199 /* 200 * Read input packet, examine its packet type, and enqueue it. 201 */ 202 enpread(es, bcbp) 203 struct enp_softc *es; 204 register BCB *bcbp; 205 { 206 register struct ether_header *enp; 207 struct mbuf *m; 208 int s, len, off, resid; 209 210 es->es_if.if_ipackets++; 211 /* 212 * Get input data length. 213 * Get pointer to ethernet header (in input buffer). 214 * Deal with trailer protocol: if type is PUP trailer 215 * get true type from first 16-bit word past data. 216 * Remember that type was trailer by setting off. 217 */ 218 len = bcbp->b_msglen - sizeof (struct ether_header); 219 enp = (struct ether_header *)ENPGETLONG(&bcbp->b_addr); 220 #define enpdataaddr(enp, off, type) \ 221 ((type)(((caddr_t)(((char *)enp)+sizeof (struct ether_header))+(off)))) 222 enp->ether_type = ntohs((u_short)enp->ether_type); 223 if (enp->ether_type >= ETHERTYPE_TRAIL && 224 enp->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 225 off = (enp->ether_type - ETHERTYPE_TRAIL) * 512; 226 if (off >= ETHERMTU) 227 return; 228 enp->ether_type = ntohs(*enpdataaddr(enp, off, u_short *)); 229 resid = ntohs(*(enpdataaddr(enp, off+2, u_short *))); 230 if (off + resid > len) 231 return; 232 len = off + resid; 233 } else 234 off = 0; 235 if (len == 0) 236 return; 237 238 /* 239 * Pull packet off interface. Off is nonzero if packet 240 * has trailing header; enpget will then force this header 241 * information to be at the front. 242 */ 243 m = enpget((u_char *)enp, len, off, &es->es_if); 244 if (m == 0) 245 return; 246 en_doproto(&es->es_if, enp, m); 247 } 248 249 enpstart(ifp) 250 struct ifnet *ifp; 251 { 252 int error = 0; 253 int s = splimp(); 254 255 if (enpput(ifp)) 256 error = ENOBUFS; 257 splx(s); 258 return (error); 259 } 260 261 /* 262 * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 263 */ 264 enpput(ifp) 265 struct ifnet *ifp; 266 { 267 register BCB *bcbp; 268 register struct enpdevice *addr; 269 register struct mbuf *mp; 270 register u_char *bp; 271 register u_int len; 272 int unit = ifp->if_unit; 273 u_char *mcp; 274 struct mbuf *m; 275 276 addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 277 again: 278 if (ringempty((RING *)&addr->enp_hostfree)) 279 return (1); 280 IF_DEQUEUE(&ifp->if_snd, m); 281 if (m == 0) return (0); 282 bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 283 bcbp->b_len = 0; 284 bp = (u_char *)ENPGETLONG(&bcbp->b_addr); 285 for (mp = m; mp; mp = mp->m_next) { 286 len = mp->m_len; 287 if (len == 0) 288 continue; 289 mcp = mtod(mp, u_char *); 290 enpcopy(mcp, bp, len); 291 bp += len; 292 bcbp->b_len += len; 293 } 294 bcbp->b_len = MAX(ETHERMIN+sizeof (struct ether_header), bcbp->b_len); 295 bcbp->b_reserved = 0; 296 if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 297 INTR_ENP(addr); 298 m_freem(m); 299 goto again; 300 } 301 302 /* 303 * Routine to copy from VERSAbus memory into mbufs. 304 * 305 * Warning: This makes the fairly safe assumption that 306 * mbufs have even lengths. 307 */ 308 struct mbuf * 309 enpget(rxbuf, totlen, off, ifp) 310 u_char *rxbuf; 311 int totlen, off; 312 struct ifnet *ifp; 313 { 314 register u_char *cp, *mcp; 315 register struct mbuf *m; 316 struct mbuf *top = 0, **mp = ⊤ 317 int len; 318 u_char *packet_end; 319 320 rxbuf += sizeof (struct ether_header); 321 cp = rxbuf; 322 packet_end = cp + totlen; 323 if (off) { 324 off += 2 * sizeof(u_short); 325 totlen -= 2 *sizeof(u_short); 326 cp = rxbuf + off; 327 } 328 329 MGETHDR(m, M_DONTWAIT, MT_DATA); 330 if (m == 0) 331 return (0); 332 m->m_pkthdr.rcvif = ifp; 333 m->m_pkthdr.len = totlen; 334 m->m_len = MHLEN; 335 336 while (totlen > 0) { 337 if (top) { 338 MGET(m, M_DONTWAIT, MT_DATA); 339 if (m == 0) { 340 m_freem(top); 341 return (0); 342 } 343 m->m_len = MLEN; 344 } 345 len = min(totlen, (packet_end - cp)); 346 if (len >= MINCLSIZE) { 347 MCLGET(m, M_DONTWAIT); 348 if (m->m_flags & M_EXT) 349 m->m_len = len = min(len, MCLBYTES); 350 else 351 len = m->m_len; 352 } else { 353 /* 354 * Place initial small packet/header at end of mbuf. 355 */ 356 if (len < m->m_len) { 357 if (top == 0 && len < max_linkhdr + m->m_len) 358 m->m_data += max_linkhdr; 359 m->m_len = len; 360 } else 361 len = m->m_len; 362 } 363 mcp = mtod(m, u_char *); 364 enpcopy(cp, mcp, (u_int)len); 365 *mp = m; 366 mp = &m->m_next; 367 totlen -= len; 368 cp += len; 369 if (cp == packet_end) 370 cp = rxbuf; 371 } 372 return (top); 373 } 374 375 enpcopy(from, to, cnt) 376 register u_char *from, *to; 377 register u_int cnt; 378 { 379 register c; 380 register short *f, *t; 381 382 if (((int)from&01) && ((int)to&01)) { 383 /* source & dest at odd addresses */ 384 *to++ = *from++; 385 --cnt; 386 } 387 if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 388 t = (short *)to; 389 f = (short *)from; 390 for (c = cnt>>1; c; --c) /* even address copy */ 391 *t++ = *f++; 392 cnt &= 1; 393 if (cnt) { /* odd len */ 394 from = (u_char *)f; 395 to = (u_char *)t; 396 *to = *from; 397 } 398 } 399 while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 400 *to++ = *from++; 401 } 402 403 /* 404 * Process an ioctl request. 405 */ 406 enpioctl(ifp, cmd, data) 407 register struct ifnet *ifp; 408 int cmd; 409 caddr_t data; 410 { 411 register struct ifaddr *ifa = (struct ifaddr *)data; 412 struct enpdevice *addr; 413 int s = splimp(), error = 0; 414 415 switch (cmd) { 416 417 case SIOCSIFADDR: 418 ifp->if_flags |= IFF_UP; 419 switch (ifa->ifa_addr.sa_family) { 420 #ifdef INET 421 case AF_INET: 422 enpinit(ifp->if_unit); 423 ((struct arpcom *)ifp)->ac_ipaddr = 424 IA_SIN(ifa)->sin_addr; 425 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 426 break; 427 #endif 428 #ifdef NS 429 case AF_NS: { 430 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 431 struct enp_softc *es = &enp_softc[ifp->if_unit]; 432 433 if (!ns_nullhost(*ina)) { 434 ifp->if_flags &= ~IFF_RUNNING; 435 addr = (struct enpdevice *) 436 enpinfo[ifp->if_unit]->ui_addr; 437 enpsetaddr(ifp->if_unit, addr, 438 ina->x_host.c_host); 439 } else 440 ina->x_host = *(union ns_host *)es->es_addr; 441 enpinit(ifp->if_unit); 442 break; 443 } 444 #endif 445 default: 446 enpinit(ifp->if_unit); 447 break; 448 } 449 break; 450 451 case SIOCSIFFLAGS: 452 if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 453 enpinit(ifp->if_unit); /* reset board */ 454 ifp->if_flags &= ~IFF_RUNNING; 455 } else if (ifp->if_flags&IFF_UP && 456 (ifp->if_flags&IFF_RUNNING) == 0) 457 enpinit(ifp->if_unit); 458 break; 459 460 default: 461 error = EINVAL; 462 } 463 splx(s); 464 return (error); 465 } 466 467 enpsetaddr(unit, addr, enaddr) 468 int unit; 469 struct enpdevice *addr; 470 u_char *enaddr; 471 { 472 473 enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr, 474 sizeof (struct ether_addr)); 475 enpinit(unit); 476 enpgetaddr(unit, addr); 477 } 478 479 enpgetaddr(unit, addr) 480 int unit; 481 struct enpdevice *addr; 482 { 483 struct enp_softc *es = &enp_softc[unit]; 484 485 enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr, 486 sizeof (struct ether_addr)); 487 printf("enp%d: hardware address %s\n", 488 unit, ether_sprintf(es->es_addr)); 489 } 490 491 /* 492 * Routines to synchronize enp and host. 493 */ 494 #ifdef notdef 495 static 496 ringinit(rp, size) 497 register RING *rp; 498 { 499 500 rp->r_rdidx = rp->r_wrtidx = 0; 501 rp->r_size = size; 502 } 503 504 static 505 ringfull(rp) 506 register RING *rp; 507 { 508 register short idx; 509 510 idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 511 return (idx == rp->r_rdidx); 512 } 513 514 static 515 fir(rp) 516 register RING *rp; 517 { 518 519 return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 520 } 521 #endif 522 523 static 524 ringempty(rp) 525 register RING *rp; 526 { 527 528 return (rp->r_rdidx == rp->r_wrtidx); 529 } 530 531 static 532 ringput(rp, v) 533 register RING *rp; 534 BCB *v; 535 { 536 register int idx; 537 538 idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 539 if (idx != rp->r_rdidx) { 540 ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v); 541 rp->r_wrtidx = idx; 542 if ((idx -= rp->r_rdidx) < 0) 543 idx += rp->r_size; 544 return (idx); /* num ring entries */ 545 } 546 return (0); 547 } 548 549 static 550 ringget(rp) 551 register RING *rp; 552 { 553 register int i = 0; 554 555 if (rp->r_rdidx != rp->r_wrtidx) { 556 i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]); 557 rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 558 } 559 return (i); 560 } 561 562 /* 563 * ENP Ram device. 564 */ 565 enpr_open(dev) 566 dev_t dev; 567 { 568 register int unit = ENPUNIT(dev); 569 struct vba_device *ui; 570 struct enpdevice *addr; 571 572 if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 573 (addr = (struct enpdevice *)ui->ui_addr) == 0) 574 return (ENODEV); 575 if (addr->enp_state != S_ENPRESET) 576 return (EACCES); /* enp is not in reset state, don't open */ 577 return (0); 578 } 579 580 /*ARGSUSED*/ 581 enpr_close(dev) 582 dev_t dev; 583 { 584 585 return (0); 586 } 587 588 enpr_read(dev, uio) 589 dev_t dev; 590 register struct uio *uio; 591 { 592 register struct iovec *iov; 593 struct enpdevice *addr; 594 595 if (uio->uio_offset > RAM_SIZE) 596 return (ENODEV); 597 iov = uio->uio_iov; 598 if (uio->uio_offset + iov->iov_len > RAM_SIZE) 599 iov->iov_len = RAM_SIZE - uio->uio_offset; 600 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 601 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0) 602 return (EFAULT); 603 enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 604 (u_char *)iov->iov_base, (u_int)iov->iov_len); 605 uio->uio_resid -= iov->iov_len; 606 iov->iov_len = 0; 607 return (0); 608 } 609 610 enpr_write(dev, uio) 611 dev_t dev; 612 register struct uio *uio; 613 { 614 register struct enpdevice *addr; 615 register struct iovec *iov; 616 617 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 618 iov = uio->uio_iov; 619 if (uio->uio_offset > RAM_SIZE) 620 return (ENODEV); 621 if (uio->uio_offset + iov->iov_len > RAM_SIZE) 622 iov->iov_len = RAM_SIZE - uio->uio_offset; 623 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0) 624 return (EFAULT); 625 enpcopy((u_char *)iov->iov_base, 626 (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 627 uio->uio_resid -= iov->iov_len; 628 iov->iov_len = 0; 629 return (0); 630 } 631 632 /*ARGSUSED*/ 633 enpr_ioctl(dev, cmd, data) 634 dev_t dev; 635 caddr_t data; 636 { 637 register unit = ENPUNIT(dev); 638 struct enpdevice *addr; 639 640 addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 641 switch(cmd) { 642 643 case ENPIOGO: 644 ENPSETLONG(&addr->enp_base, addr); 645 addr->enp_intrvec = enp_softc[unit].es_ivec; 646 ENP_GO(addr, ENPSTART); 647 DELAY(200000); 648 enpinit(unit); 649 /* 650 * Fetch Ethernet address after link level 651 * is booted (firmware copies manufacturer's 652 * address from on-board ROM). 653 */ 654 enpgetaddr(unit, addr); 655 addr->enp_state = S_ENPRUN; 656 break; 657 658 case ENPIORESET: 659 RESET_ENP(addr); 660 addr->enp_state = S_ENPRESET; 661 DELAY(100000); 662 break; 663 default: 664 return (EINVAL); 665 } 666 return (0); 667 } 668 #endif 669