📄 if_ex.c
字号:
* interrupts by EXOS are disabled. */exstart(ifp)struct ifnet *ifp;{ int unit = ifp->if_unit; struct vba_device *ui = exinfo[unit]; register struct ex_softc *xs = &ex_softc[unit]; struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; register struct ex_msg *bp; register struct mbuf *m; int len; register struct ifvba *pkb; struct mbuf *m0 = 0; register int nb = 0, tlen = 0; union l_util { u_long l; struct i86_long i; } l_util; if (xs->xs_ntrb >= NTRB) return; if (xs->xs_pkblist == 0) { printf("ex%d: vbinfo exhausted, would panic", unit); return; } IF_DEQUEUE(&xs->xs_if.if_snd, m); if (m == 0) return; /* * Get a transmit request. */ if ((bp = exgetcbuf(xs, LLRTRANSMIT)) == (struct ex_msg *)0) { m_freem(m); printf("exstart: no command buffers\n"); return; } xs->xs_ntrb++; GetPkBuf(bp, pkb); pkb->iff_mbuf = m; /* save mbuf pointer to free when done */ /* * point directly to the first group of mbufs to be transmitted. The * hardware can only support NFRAGMENTS descriptors. */ while (m && ((nb < NFRAGMENTS-1) || (m->m_next == 0)) ) { l_util.l = BUSADDR(mtod(m, caddr_t)); bp->mb_et.et_blks[nb].bb_len = (u_short)m->m_len; bp->mb_et.et_blks[nb].bb_addr = l_util.i; if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { /* Here, the phys memory for the mbuf is out of range for the vmebus to talk to it */ if (m == pkb->iff_mbuf) pkb->iff_mbuf = 0; break; } tlen += m->m_len; m0 = m; m = m->m_next; nb++; } /* 0 end of chain pointed to by iff_mbuf, to be freed when xmit done */ if (m0) m0->m_next = 0; /* * if not all of the descriptors would fit then merge remaining data * into the transmit buffer, and point to it. Note: the mbufs are freed * during the merge, they do not have to be freed when we get the * transmit interrupt. */ if (m) { if (m == pkb->iff_mbuf) { printf("ex%d: exstart insanity\n", unit); pkb->iff_mbuf = 0; } len = if_vbaput(pkb->iff_buffer, m, 0); l_util.l = BUSADDR(pkb->iff_buffer); bp->mb_et.et_blks[nb].bb_len = (u_short)len; bp->mb_et.et_blks[nb].bb_addr = l_util.i; tlen += len; nb++; } /* * If the total length of the packet is too small, * pad the last fragment. (May run into very obscure problems) */ if (tlen < sizeof(struct ether_header) + ETHERMIN) { len = (ETHERMIN + sizeof(struct ether_header)) - tlen; bp->mb_et.et_blks[nb-1].bb_len += (u_short)len; tlen += len;#ifdef notdef if (l_util.l + m->m_len > BUSADDR(VB_MAXADDR24)) { must copy last frag into private buffer }#endif } /* set number of fragments in descriptor */ bp->mb_et.et_nblock = nb; bp->mb_status |= MH_EXOS; movow(&exaddr->ex_portb, EX_NTRUPT);}/* * interrupt service routine. */exintr(unit) int unit;{ register struct ex_softc *xs = &ex_softc[unit]; register struct ex_msg *bp = xs->xs_x2hnext; struct vba_device *ui = exinfo[unit]; struct exdevice *exaddr = (struct exdevice *)ui->ui_addr; struct ex_msg *next_bp; while ((bp->mb_status & MH_OWNER) == MH_HOST) { switch (bp->mb_rqst) { case LLRECEIVE: if (--xs->xs_nrec < 0) { printf("ex%d: internal receive check\n", unit); xs->xs_nrec = 0; } exrecv(unit, bp); FreePkBuf(bp->mb_pkb); bp->mb_pkb = (struct ifvba *)0; exhangrcv(unit); break; case LLTRANSMIT: case LLRTRANSMIT: if (--xs->xs_ntrb < 0) { printf("ex%d: internal transmit check\n", unit); xs->xs_ntrb = 0; } xs->xs_if.if_opackets++; if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) ; else if (bp->mb_rply & LLXM_1RTRY) xs->xs_if.if_collisions++; else if (bp->mb_rply & LLXM_RTRYS) xs->xs_if.if_collisions += 2; /* guess */ else if (bp->mb_rply & LLXM_ERROR) if (xs->xs_if.if_oerrors++ % 100 == 0) printf("ex%d: 100 transmit errors=%b\n", unit, bp->mb_rply, XMIT_BITS); if (bp->mb_pkb->iff_mbuf) { m_freem(bp->mb_pkb->iff_mbuf); bp->mb_pkb->iff_mbuf = (struct mbuf *)0; } FreePkBuf(bp->mb_pkb); bp->mb_pkb = (struct ifvba *)0; exstart(&xs->xs_if); exhangrcv(unit); break; case LLNET_STSTCS: xs->xs_if.if_ierrors += xs->xs_xsa.sa_crc; xs->xs_flags &= ~EX_STATPENDING; case LLNET_ADDRS: case LLNET_RECV: if (bp->mb_rply == LL_OK || bp->mb_rply == LLXM_NSQE) ; else printf("ex%d: %s, request 0x%x, reply 0x%x\n", unit, "unsucessful stat or address change", bp->mb_rqst, bp->mb_rply); break; default: printf("ex%d: unknown reply 0x%x", unit, bp->mb_rqst); } bp->mb_length = MBDATALEN; next_bp = bp->mb_next; bp->mb_status |= MH_EXOS; /* free up buffer */ bp = next_bp; /* paranoia about race */ movow(&exaddr->ex_portb, EX_NTRUPT); /* tell EXOS about it */ } xs->xs_x2hnext = bp;}/* * Get a request buffer, fill in standard values, advance pointer. */struct ex_msg *exgetcbuf(xs, req)struct ex_softc *xs;int req;{ register struct ex_msg *bp; struct ifvba *pkb; int s = splimp(); bp = xs->xs_h2xnext; if ((bp->mb_status & MH_OWNER) == MH_EXOS) { splx(s); return (struct ex_msg *)0; } xs->xs_h2xnext = bp->mb_next; bp->mb_1rsrv = 0; bp->mb_rqst = req; bp->mb_length = MBDATALEN; bp->mb_pkb = (struct ifvba *)0; splx(s); return bp;}/* * Process Ethernet receive completion: If input error just drop packet, * otherwise examine packet to determine type. If can't determine length from * type, then have to drop packet, otherwise decapsulate packet based on type * and pass to type-specific higher-level input routine. */exrecv(unit, bp)int unit;register struct ex_msg *bp;{ register struct ex_softc *xs = &ex_softc[unit]; register struct ether_header *eh; register struct mbuf *m; int len, off, resid; register struct ifqueue *inq; int s; xs->xs_if.if_ipackets++; /* total length - header - crc */ len = bp->mb_er.er_blks[0].bb_len - sizeof(struct ether_header) - 4; if (bp->mb_rply != LL_OK) { if (xs->xs_if.if_ierrors++ % 100 == 0) printf("ex%d: 100 receive errors=%b\n", unit, bp->mb_rply, RECV_BITS); return; } eh = (struct ether_header *)(bp->mb_pkb->iff_buffer); /* * Deal with trailer protocol: if type is PUP trailer get true type from * first 16-bit word past data. Remember that type was trailer by * setting off. */ eh->ether_type = ntohs((u_short)eh->ether_type);#define exdataaddr(eh, off, type) ((type)(((caddr_t)((eh)+1)+(off)))) if (eh->ether_type >= ETHERTYPE_TRAIL && eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; if (off >= ETHERMTU) return; /* sanity */ eh->ether_type = ntohs(*exdataaddr(eh, off, u_short *)); resid = ntohs(*(exdataaddr(eh, off+2, u_short *))); if (off + resid > len) return; /* sanity */ len = off + resid; } else off = 0; if (len == 0) return; /* * Pull packet off interface. Off is nonzero if packet * has trailing header; if_vbaget will then force this header * information to be at the front, but we still have to drop * the type and length which are at the front of any trailer data. */ m = if_vbaget(bp->mb_pkb->iff_buffer, len, off, &xs->xs_if, 0); if (m == 0) return; ether_input(&xs->xs_if, eh, m); return;}/* * Hang a receive request. This routine is called by exinit and excdint, * with interrupts disabled in both cases. */exhangrcv(unit) int unit;{ register struct ex_softc *xs = &ex_softc[unit]; register struct ex_msg *bp; register struct ifvba *pkb; short mustint = 0; union l_util { u_long l; struct i86_long i; } l_util; while (xs->xs_nrec < NREC) { if (xs->xs_pkblist == (struct ifvba *)0) break; if ((bp = exgetcbuf(xs, LLRECEIVE)) == (struct ex_msg *)0) { break; } GetPkBuf(bp, pkb); pkb->iff_mbuf = 0; xs->xs_nrec += 1; bp->mb_er.er_nblock = 1; bp->mb_er.er_blks[0].bb_len = EXMAXRBUF; l_util.l = BUSADDR(pkb->iff_buffer); bp->mb_er.er_blks[0].bb_addr = l_util.i; bp->mb_status |= MH_EXOS; mustint = 1; } if (mustint == 0) return; movow(&((struct exdevice *)exinfo[unit]->ui_addr)->ex_portb, EX_NTRUPT);}/* * Ethernet output routine is ether_output(). *//* * Watchdog routine (currently not used). Might use this to get stats from EXOS. */exwatch(unit)int unit;{ struct exdevice *exaddr = (struct exdevice *)exinfo[unit]->ui_addr; register struct ex_softc *xs = &ex_softc[unit]; register struct ex_msg *bp; int s = splimp(); if (xs->xs_flags & EX_STATPENDING) goto exspnd; if ((bp = exgetcbuf(xs, LLNET_STSTCS)) == (struct ex_msg *)0) { splx(s); return; } xs->xs_flags |= EX_STATPENDING; bp->mb_ns.ns_mask = READ_OBJ; bp->mb_ns.ns_rsrv = 0; bp->mb_ns.ns_nobj = 8; bp->mb_ns.ns_xobj = 0; bp->mb_ns.ns_bufp = P_BUSADDR(xs->xs_qbaddr) + SA_OFFSET; bp->mb_status |= MH_EXOS; movow(&exaddr->ex_portb, EX_NTRUPT);exspnd: splx(s); xs->xs_if.if_timer = EXWATCHINTVL;}/* * Process an ioctl request. */exioctl(ifp, cmd, data) register struct ifnet *ifp; int cmd; caddr_t data;{ register struct ifaddr *ifa = (struct ifaddr *)data; register struct ex_softc *xs = &ex_softc[ifp->if_unit]; int s = splimp(), error = 0; switch (cmd) { case SIOCSIFADDR: ifp->if_flags |= IFF_UP; exinit(ifp->if_unit); switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); break;#endif#ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(xs->xs_addr); else ex_setaddr(ina->x_host.c_host,ifp->if_unit); break; }#endif } break; case SIOCSIFFLAGS: if ((ifp->if_flags & IFF_UP) == 0 && xs->xs_flags & EX_RUNNING) { movow(&((struct exdevice *) (exinfo[ifp->if_unit]->ui_addr))->ex_porta, EX_RESET); xs->xs_flags &= ~EX_RUNNING; } else if (ifp->if_flags & IFF_UP && (xs->xs_flags & EX_RUNNING) == 0) exinit(ifp->if_unit); break; default: error = EINVAL; } splx(s); return (error);}/* * set ethernet address for unit */ex_setaddr(physaddr, unit) u_char *physaddr; int unit;{ register struct ex_softc *xs = &ex_softc[unit]; if (physaddr) { xs->xs_flags |= EX_SETADDR; bcopy((caddr_t)physaddr, (caddr_t)xs->xs_addr, 6); } ex_setmulti((u_char *)xs->xs_addr, unit, PHYSSLOT);}/* * Enable multicast reception for unit. */ex_setmulti(linkaddr, unit, slot) u_char *linkaddr; int unit, slot;{ register struct ex_softc *xs = &ex_softc[unit]; struct vba_device *ui = exinfo[unit]; register struct exdevice *addr= (struct exdevice *)ui->ui_addr; register struct ex_msg *bp; if (!(xs->xs_flags & EX_RUNNING)) return; bp = exgetcbuf(xs, LLNET_ADDRS); bp->mb_na.na_mask = READ_OBJ|WRITE_OBJ; bp->mb_na.na_slot = slot; bcopy((caddr_t)linkaddr, (caddr_t)bp->mb_na.na_addrs, 6); bp->mb_status |= MH_EXOS; movow(&addr->ex_portb, EX_NTRUPT); bp = xs->xs_x2hnext; while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */#ifdef DEBUG log(LOG_DEBUG, "ex%d: %s %s (slot %d)\n", unit, (slot == PHYSSLOT ? "reset addr" : "add multicast" ether_sprintf(bp->mb_na.na_addrs), slot);#endif /* * Now, re-enable reception on slot. */ bp = exgetcbuf(xs, LLNET_RECV); bp->mb_nr.nr_mask = ENABLE_RCV|READ_OBJ|WRITE_OBJ; bp->mb_nr.nr_slot = slot; bp->mb_status |= MH_EXOS; movow(&addr->ex_portb, EX_NTRUPT); bp = xs->xs_x2hnext; while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */ ;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -