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.6 (Berkeley) 03/28/90 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 = ether_output; 133 ifp->if_start = enpstart; 134 ifp->if_reset = enpreset; 135 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 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 ether_input(&es->es_if, enp, m); 247 } 248 249 enpstart(ifp) 250 struct ifnet *ifp; 251 { 252 253 if (enpput(ifp)) 254 return (ENOBUFS); 255 else 256 return (0); 257 } 258 259 /* 260 * Routine to copy from mbuf chain to transmitter buffer on the VERSAbus. 261 */ 262 enpput(ifp) 263 struct ifnet *ifp; 264 { 265 register BCB *bcbp; 266 register struct enpdevice *addr; 267 register struct mbuf *mp; 268 register u_char *bp; 269 register u_int len; 270 int unit = ifp->if_unit, ret = 1; 271 struct mbuf *m; 272 273 addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 274 again: 275 if (ringempty((RING *)&addr->enp_hostfree)) { 276 /* ifp->if_flags |= IFF_OACTIVE; */ 277 return (ret); 278 } 279 IF_DEQUEUE(&ifp->if_snd, m); 280 if (m == 0) { 281 ifp->if_flags &= ~IFF_OACTIVE; 282 return (0); 283 } 284 bcbp = (BCB *)ringget((RING *)&addr->enp_hostfree); 285 bcbp->b_len = 0; 286 bp = (u_char *)ENPGETLONG(&bcbp->b_addr); 287 for (mp = m; mp; mp = mp->m_next) { 288 len = mp->m_len; 289 if (len == 0) 290 continue; 291 enpcopy(mtod(mp, u_char *), bp, len); 292 bp += len; 293 bcbp->b_len += len; 294 } 295 bcbp->b_len = max(ETHERMIN+sizeof (struct ether_header), bcbp->b_len); 296 bcbp->b_reserved = 0; 297 if (ringput((RING *)&addr->enp_toenp, bcbp) == 1) 298 INTR_ENP(addr); 299 m_freem(m); 300 ret = 0; 301 goto again; 302 } 303 304 /* 305 * Routine to copy from VERSAbus memory into mbufs. 306 * 307 * Warning: This makes the fairly safe assumption that 308 * mbufs have even lengths. 309 */ 310 struct mbuf * 311 enpget(rxbuf, totlen, off, ifp) 312 u_char *rxbuf; 313 int totlen, off; 314 struct ifnet *ifp; 315 { 316 register u_char *cp; 317 register struct mbuf *m; 318 struct mbuf *top = 0, **mp = ⊤ 319 int len; 320 u_char *packet_end; 321 322 rxbuf += sizeof (struct ether_header); 323 cp = rxbuf; 324 packet_end = cp + totlen; 325 if (off) { 326 off += 2 * sizeof(u_short); 327 totlen -= 2 *sizeof(u_short); 328 cp = rxbuf + off; 329 } 330 331 MGETHDR(m, M_DONTWAIT, MT_DATA); 332 if (m == 0) 333 return (0); 334 m->m_pkthdr.rcvif = ifp; 335 m->m_pkthdr.len = totlen; 336 m->m_len = MHLEN; 337 338 while (totlen > 0) { 339 if (top) { 340 MGET(m, M_DONTWAIT, MT_DATA); 341 if (m == 0) { 342 m_freem(top); 343 return (0); 344 } 345 m->m_len = MLEN; 346 } 347 len = min(totlen, (packet_end - cp)); 348 if (len >= MINCLSIZE) { 349 MCLGET(m, M_DONTWAIT); 350 if (m->m_flags & M_EXT) 351 m->m_len = len = min(len, MCLBYTES); 352 else 353 len = m->m_len; 354 } else { 355 /* 356 * Place initial small packet/header at end of mbuf. 357 */ 358 if (len < m->m_len) { 359 if (top == 0 && len + max_linkhdr <= m->m_len) 360 m->m_data += max_linkhdr; 361 m->m_len = len; 362 } else 363 len = m->m_len; 364 } 365 enpcopy(cp, mtod(m, u_char *), (u_int)len); 366 *mp = m; 367 mp = &m->m_next; 368 totlen -= len; 369 cp += len; 370 if (cp == packet_end) 371 cp = rxbuf; 372 } 373 return (top); 374 } 375 376 enpcopy(from, to, cnt) 377 register u_char *from, *to; 378 register u_int cnt; 379 { 380 register c; 381 register short *f, *t; 382 383 if (((int)from&01) && ((int)to&01)) { 384 /* source & dest at odd addresses */ 385 *to++ = *from++; 386 --cnt; 387 } 388 if (cnt > 1 && (((int)to&01) == 0) && (((int)from&01) == 0)) { 389 t = (short *)to; 390 f = (short *)from; 391 for (c = cnt>>1; c; --c) /* even address copy */ 392 *t++ = *f++; 393 cnt &= 1; 394 if (cnt) { /* odd len */ 395 from = (u_char *)f; 396 to = (u_char *)t; 397 *to = *from; 398 } 399 } 400 while ((int)cnt-- > 0) /* one of the address(es) must be odd */ 401 *to++ = *from++; 402 } 403 404 /* 405 * Process an ioctl request. 406 */ 407 enpioctl(ifp, cmd, data) 408 register struct ifnet *ifp; 409 int cmd; 410 caddr_t data; 411 { 412 register struct ifaddr *ifa = (struct ifaddr *)data; 413 struct enpdevice *addr; 414 int s = splimp(), error = 0; 415 416 switch (cmd) { 417 418 case SIOCSIFADDR: 419 ifp->if_flags |= IFF_UP; 420 switch (ifa->ifa_addr->sa_family) { 421 #ifdef INET 422 case AF_INET: 423 enpinit(ifp->if_unit); 424 ((struct arpcom *)ifp)->ac_ipaddr = 425 IA_SIN(ifa)->sin_addr; 426 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 427 break; 428 #endif 429 #ifdef NS 430 case AF_NS: { 431 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; 432 struct enp_softc *es = &enp_softc[ifp->if_unit]; 433 434 if (!ns_nullhost(*ina)) { 435 ifp->if_flags &= ~IFF_RUNNING; 436 addr = (struct enpdevice *) 437 enpinfo[ifp->if_unit]->ui_addr; 438 enpsetaddr(ifp->if_unit, addr, 439 ina->x_host.c_host); 440 } else 441 ina->x_host = *(union ns_host *)es->es_addr; 442 enpinit(ifp->if_unit); 443 break; 444 } 445 #endif 446 default: 447 enpinit(ifp->if_unit); 448 break; 449 } 450 break; 451 452 case SIOCSIFFLAGS: 453 if ((ifp->if_flags&IFF_UP) == 0 && ifp->if_flags&IFF_RUNNING) { 454 enpinit(ifp->if_unit); /* reset board */ 455 ifp->if_flags &= ~IFF_RUNNING; 456 } else if (ifp->if_flags&IFF_UP && 457 (ifp->if_flags&IFF_RUNNING) == 0) 458 enpinit(ifp->if_unit); 459 break; 460 461 default: 462 error = EINVAL; 463 } 464 splx(s); 465 return (error); 466 } 467 468 enpsetaddr(unit, addr, enaddr) 469 int unit; 470 struct enpdevice *addr; 471 u_char *enaddr; 472 { 473 474 enpcopy(enaddr, addr->enp_addr.e_baseaddr.ea_addr, 475 sizeof (struct ether_addr)); 476 enpinit(unit); 477 enpgetaddr(unit, addr); 478 } 479 480 enpgetaddr(unit, addr) 481 int unit; 482 struct enpdevice *addr; 483 { 484 struct enp_softc *es = &enp_softc[unit]; 485 486 enpcopy(addr->enp_addr.e_baseaddr.ea_addr, es->es_addr, 487 sizeof (struct ether_addr)); 488 printf("enp%d: hardware address %s\n", 489 unit, ether_sprintf(es->es_addr)); 490 } 491 492 /* 493 * Routines to synchronize enp and host. 494 */ 495 #ifdef notdef 496 static 497 ringinit(rp, size) 498 register RING *rp; 499 { 500 501 rp->r_rdidx = rp->r_wrtidx = 0; 502 rp->r_size = size; 503 } 504 505 static 506 ringfull(rp) 507 register RING *rp; 508 { 509 register short idx; 510 511 idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 512 return (idx == rp->r_rdidx); 513 } 514 515 static 516 fir(rp) 517 register RING *rp; 518 { 519 520 return (rp->r_rdidx != rp->r_wrtidx ? rp->r_slot[rp->r_rdidx] : 0); 521 } 522 #endif 523 524 static 525 ringempty(rp) 526 register RING *rp; 527 { 528 529 return (rp->r_rdidx == rp->r_wrtidx); 530 } 531 532 static 533 ringput(rp, v) 534 register RING *rp; 535 BCB *v; 536 { 537 register int idx; 538 539 idx = (rp->r_wrtidx + 1) & (rp->r_size-1); 540 if (idx != rp->r_rdidx) { 541 ENPSETLONG(&rp->r_slot[rp->r_wrtidx], v); 542 rp->r_wrtidx = idx; 543 if ((idx -= rp->r_rdidx) < 0) 544 idx += rp->r_size; 545 return (idx); /* num ring entries */ 546 } 547 return (0); 548 } 549 550 static 551 ringget(rp) 552 register RING *rp; 553 { 554 register int i = 0; 555 556 if (rp->r_rdidx != rp->r_wrtidx) { 557 i = ENPGETLONG(&rp->r_slot[rp->r_rdidx]); 558 rp->r_rdidx = (++rp->r_rdidx) & (rp->r_size-1); 559 } 560 return (i); 561 } 562 563 /* 564 * ENP Ram device. 565 */ 566 enpr_open(dev) 567 dev_t dev; 568 { 569 register int unit = ENPUNIT(dev); 570 struct vba_device *ui; 571 struct enpdevice *addr; 572 573 if (unit >= NENP || (ui = enpinfo[unit]) == 0 || ui->ui_alive == 0 || 574 (addr = (struct enpdevice *)ui->ui_addr) == 0) 575 return (ENODEV); 576 if (addr->enp_state != S_ENPRESET) 577 return (EACCES); /* enp is not in reset state, don't open */ 578 return (0); 579 } 580 581 /*ARGSUSED*/ 582 enpr_close(dev) 583 dev_t dev; 584 { 585 586 return (0); 587 } 588 589 enpr_read(dev, uio) 590 dev_t dev; 591 register struct uio *uio; 592 { 593 register struct iovec *iov; 594 struct enpdevice *addr; 595 596 if (uio->uio_offset > RAM_SIZE) 597 return (ENODEV); 598 iov = uio->uio_iov; 599 if (uio->uio_offset + iov->iov_len > RAM_SIZE) 600 iov->iov_len = RAM_SIZE - uio->uio_offset; 601 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 602 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 0) == 0) 603 return (EFAULT); 604 enpcopy((u_char *)&addr->enp_ram[uio->uio_offset], 605 (u_char *)iov->iov_base, (u_int)iov->iov_len); 606 uio->uio_resid -= iov->iov_len; 607 iov->iov_len = 0; 608 return (0); 609 } 610 611 enpr_write(dev, uio) 612 dev_t dev; 613 register struct uio *uio; 614 { 615 register struct enpdevice *addr; 616 register struct iovec *iov; 617 618 addr = (struct enpdevice *)enpinfo[ENPUNIT(dev)]->ui_addr; 619 iov = uio->uio_iov; 620 if (uio->uio_offset > RAM_SIZE) 621 return (ENODEV); 622 if (uio->uio_offset + iov->iov_len > RAM_SIZE) 623 iov->iov_len = RAM_SIZE - uio->uio_offset; 624 if (useracc(iov->iov_base, (unsigned)iov->iov_len, 1) == 0) 625 return (EFAULT); 626 enpcopy((u_char *)iov->iov_base, 627 (u_char *)&addr->enp_ram[uio->uio_offset], (u_int)iov->iov_len); 628 uio->uio_resid -= iov->iov_len; 629 uio->uio_offset += iov->iov_len; 630 iov->iov_len = 0; 631 return (0); 632 } 633 634 /*ARGSUSED*/ 635 enpr_ioctl(dev, cmd, data) 636 dev_t dev; 637 caddr_t data; 638 { 639 register unit = ENPUNIT(dev); 640 struct enpdevice *addr; 641 642 addr = (struct enpdevice *)enpinfo[unit]->ui_addr; 643 switch(cmd) { 644 645 case ENPIOGO: 646 ENPSETLONG(&addr->enp_base, addr); 647 addr->enp_intrvec = enp_softc[unit].es_ivec; 648 ENP_GO(addr, ENPSTART); 649 DELAY(200000); 650 enpinit(unit); 651 /* 652 * Fetch Ethernet address after link level 653 * is booted (firmware copies manufacturer's 654 * address from on-board ROM). 655 */ 656 enpgetaddr(unit, addr); 657 addr->enp_state = S_ENPRUN; 658 break; 659 660 case ENPIORESET: 661 RESET_ENP(addr); 662 addr->enp_state = S_ENPRESET; 663 DELAY(100000); 664 break; 665 default: 666 return (EINVAL); 667 } 668 return (0); 669 } 670 #endif 671