📄 if_bp.c
字号:
#ifdef UNIX int unit = minor (dev);#endif /* UNIX */#if defined (BSD43_DRIVER) || defined (UNIX) FAST BP_SOFTC *bs = BP_SOFTC_P [unit];#endif FAST struct mbuf *m; while (bs->bs_if.if_snd.ifq_head) /* while queue not empty */ { IF_DEQUEUE(&bs->bs_if.if_snd, m); /* get next from queue */ if (bpPut (bs, m) == ERROR) /* if couldn't send */ {#if defined (BSD43_DRIVER) || defined (UNIX) /* vxWorks BSD 4.4 ether_output() doesn't bump statistic. */ bs->bs_if.if_opackets--; /* it wasn't sent! */#endif bs->bs_if.if_oerrors++; /* it was an error */ m_freem (m); /* free the mbufs */ }#if !defined (BSD43_DRIVER) && !defined (UNIX) else /* bump statistic for BSD 4.4 vxWorks driver. */ bs->bs_if.if_opackets++; #endif } }#if defined (BSD43_DRIVER) || defined (UNIX)/********************************************************************************* bpOutput - net output routine** Encapsulate a packet of type family for the local net.* Use trailer local net encapsulation if enough data in first* packet leaves a multiple of 512 bytes of data in remainder.** RETURNS: 0 if successful, errno otherwise (as per network requirements)*/LOCAL int bpOutput ( struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst ) {#ifdef UNIX return (ether_output (ifp, m0, dst, bpStart, &(BP_SOFTC_P [ifp->if_unit])->bs_ac));#else /* UNIX */ return (ether_output (ifp, m0, dst, (FUNCPTR)bpStart, &BP_SOFTC_P [ifp->if_unit]->bs_ac));#endif /* UNIX */ }#endif/********************************************************************************* bpPut - copy from mbuf chain to shared memory buffer** RETURNS: OK or ERROR if no room left in free ring*/LOCAL STATUS bpPut ( FAST BP_SOFTC *bs, FAST struct mbuf *m ) { FAST BUF_NODE *pBufNode; u_char *bufStart; int len; if ((pBufNode = (BUF_NODE *) ringget ((RING *) bs->bs_pFreeRing)) == NULL) return (ERROR); pBufNode = ItoKval (pBufNode, BUF_NODE *, bs->bs_pAnchor); bufStart = ItoKval (pBufNode->b_addr, u_char *, bs->bs_pAnchor);#ifdef UNIX len = copy_from_mbufs (bufStart, m, len);#else /* UNIX */ copy_from_mbufs (bufStart, m, len);#endif /* UNIX */ len = max (MINPKTSIZE, len); pBufNode->b_len = BP_HTONS (len);#ifndef UNIX /* call output hook if any */ if ((etherOutputHookRtn != NULL) && (* etherOutputHookRtn) (&bs->bs_if, bufStart, pBufNode->b_len)) return (OK); /* output hook has already processed packet */#endif /* UNIX */ /* send to specified processor: * proc number is in last byte of Ethernet address */ bpXmit (bs, pBufNode, (int) ((struct ether_header *)#ifdef UNIX (bufStart))->ether_dhost.ether_addr_octet[5], bs->bs_procNum);#else /* UNIX */ (bufStart))->ether_dhost[5], bs->bs_procNum);#endif /* UNIX */ return (OK); }/********************************************************************************* bpXmit - transmit buffer*/LOCAL void bpXmit ( FAST BP_SOFTC *bs, BUF_NODE *pBufNode, int destProcNum, /* destination CPU */ int srcProcNum /* originator */ ) { BP_ANCHOR *pAnchor = bs->bs_pAnchor; u_char *buf; FAST CPU_DESC *pCpu; FAST BUF_NODE *pBufNode0; if (destProcNum < 0 || destProcNum >= MAXCPU) { /* broadcast to all CPUs on network */ buf = ItoKval (pBufNode->b_addr, u_char *, pAnchor); for (destProcNum = MAXCPU - 1; destProcNum >= 0; --destProcNum) { pCpu = &bs->bs_pHdr->hdr_cpuDesc[destProcNum]; if (DEBUG_OPTION_3) dbgprintf ("bp: broadcast packet from %d\n", srcProcNum, 0, 0, 0, 0, 0); if (!pCpu->cd_active) continue; if ((pBufNode0 = (BUF_NODE *) ringget ((RING *) bs->bs_pFreeRing)) == NULL) break; pBufNode0 = ItoKval (pBufNode0, BUF_NODE *, pAnchor); pBufNode0->b_len = pBufNode->b_len; bcopy ((caddr_t) buf, (caddr_t) ItoKval (pBufNode0->b_addr, u_char *, pAnchor), BP_NTOHS (pBufNode->b_len)); if (ringput (ItoKval (pCpu->cd_pInputRing, RING *, pAnchor), KtoIval (pBufNode0, int, pAnchor)) == 0) { /* if input ring was full, then put bufNode back on free ring */ if (DEBUG_OPTION_2) dbgprintf ("bp: dropped packet\n", 0,0,0,0,0,0); (void)ringput ((RING *) bs->bs_pFreeRing, KtoIval (pBufNode0, int, pAnchor)); } else { /* if input ring was empty, then interrupt destination CPU */ bpIntGen (pCpu, srcProcNum); } } (void) ringput ((RING *) bs->bs_pFreeRing, KtoIval (pBufNode, int, pAnchor)); } else { pCpu = &bs->bs_pHdr->hdr_cpuDesc [destProcNum]; if (DEBUG_OPTION_3) dbgprintf ("bp: packet from %d for %d\n", srcProcNum, destProcNum, 0, 0, 0, 0); if (!pCpu->cd_active) (void) ringput ((RING *) bs->bs_pFreeRing, KtoIval (pBufNode, int, pAnchor)); else if (ringput (ItoKval (pCpu->cd_pInputRing, RING *, pAnchor), KtoIval (pBufNode, int, pAnchor)) == 0) { /* input ring was full, then put bufNode back on free ring */ if (DEBUG_OPTION_2) dbgprintf ("bp: dropped packet\n", 0,0,0,0,0,0); (void) ringput ((RING *) bs->bs_pFreeRing, KtoIval (pBufNode, int, pAnchor)); } else { /* input ring had room, then interrupt destination CPU */ bpIntGen (pCpu, srcProcNum); } } }#ifdef UNIX/********************************************************************************* bpPollUnix - UNIX backplane poll** This routine is called by UNIX's timeout routine to poll the* backplane input rings for this CPU.*/LOCAL void bpPollUnix () { FAST int unit; for (unit = 0; unit < NBP; unit++) { /* if header structure non-zero then unit is initialized */ if (bp_softc[unit].bs_pHdr) bpintr (unit); } /* loop forever, with a delay of 1 */ timeout (bpPollUnix, (caddr_t)0, 1); }#else /* UNIX *//********************************************************************************* bpPollTask - backplane poll task** This routine is spawned as task to poll the backplane input rings for* this CPU. It is only used if no backplane interrupt mechanism is* used.** NOMANUAL*/void bpPollTask (void) { FAST int unit; FAST BP_SOFTC *bs; FOREVER { for (unit = 0; unit < NBP; unit++) { bs = BP_SOFTC_P [unit]; if (bs != NULL && !bs->bs_readPending) { bs->bs_readPending = TRUE; if (bs->bs_pInputRing != NULL) (void) netJobAdd ((FUNCPTR)bpReadAll, unit,0,0,0,0); } } } }/********************************************************************************* bpIntAck - acknowledge our backplane interrupt*/LOCAL void bpIntAck ( FAST BP_SOFTC *bs ) { switch (bs->bs_intType) { case BP_INT_NONE: case BP_INT_MAILBOX_1: case BP_INT_MAILBOX_2: case BP_INT_MAILBOX_4: case BP_INT_MAILBOX_R1: case BP_INT_MAILBOX_R2: case BP_INT_MAILBOX_R4: break; /* bus interrupt: * arg1 = level * arg2 = vector */ case BP_INT_BUS: sysBusIntAck (bs->bs_intArg1); break; } }#endif /* UNIX *//********************************************************************************* bpConnect - connect to our backplane using the requested interrupt type** RETURNS: OK or ERROR if interrupt type not supported*/LOCAL STATUS bpConnect ( FAST BP_SOFTC *bs, FAST int unit ) { STATUS status; switch (bs->bs_intType) { case BP_INT_NONE: /* no interprocessor interrupt - spawn background polling task */#ifdef UNIX { static BOOL bpIsPolling = FALSE; if (!bpIsPolling) { bpIsPolling = TRUE; timeout (bpPollUnix, (caddr_t)0, 1); } status = OK; }#else /* UNIX */ bpPollTaskId = taskSpawn ("bpPollTask", bpPollTaskPriority, bpPollTaskOptions, bpPollTaskStackSize, (FUNCPTR) bpPollTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); status = bpPollTaskId == ERROR ? ERROR : OK;#endif /* UNIX */ break; case BP_INT_MAILBOX_1: case BP_INT_MAILBOX_2: case BP_INT_MAILBOX_4: case BP_INT_MAILBOX_R1: case BP_INT_MAILBOX_R2: case BP_INT_MAILBOX_R4: /* interrupt by mailbox (write to bus address): * arg1 = bus address space * arg2 = address * arg3 = value */#ifdef UNIX printf ("bp%d: bpConnect interrupt type not implemented\n", unit); status = ERROR;#else /* UNIX */ status = sysMailboxConnect ((FUNCPTR)bpintr, unit);#endif /* UNIX */ break; case BP_INT_BUS: /* bus interrupt: * arg1 = level * arg2 = vector */#ifdef UNIX status = OK; /* nothing to do, done in kernel configuration */#else /* UNIX */ status = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (bs->bs_intArg2), bpintr, unit);#endif /* UNIX */ break; default: printf ("bp%d: bpConnect bad interrupt type: %d\n", unit, bs->bs_intType); status = ERROR; break; } return (status); }/********************************************************************************* bpIntEnable - enable our backplane interrupt** RETURNS: OK or ERROR*/LOCAL STATUS bpIntEnable ( FAST BP_SOFTC *bs ) { STATUS status; int unit = bs->bs_if.if_unit; switch (bs->bs_intType) { case BP_INT_NONE: status = OK; /* no interrupt (polling) */ break; case BP_INT_MAILBOX_1: case BP_INT_MAILBOX_2: case BP_INT_MAILBOX_4: case BP_INT_MAILBOX_R1: case BP_INT_MAILBOX_R2: case BP_INT_MAILBOX_R4: /* interrupt by mailbox (write to bus address): * arg1 = bus address space * arg2 = address * arg3 = value */#ifdef UNIX status = ERROR; printf ("bp%d: bpIntEnable interrupt type 0x%x not implemented\n", unit, bs->bs_intType);#else /* UNIX */ status = sysMailboxEnable ((char *) bs->bs_intArg2); if (status == ERROR) printf ("bp%d: error enabling mailbox interrupt addr 0x%x.\n", unit, bs->bs_intArg2);#endif /* UNIX */ break; case BP_INT_BUS: /* bus interrupt: * arg1 = level * arg2 = vector */#ifdef UNIX status = OK; /* nothing to do */#else /* UNIX */ status = sysIntEnable (bs->bs_intArg1); if (status == ERROR) printf ("bp%d: error enabling bus interrupt level %d.\n", unit, bs->bs_intArg1);#endif /* UNIX */ break; default: printf ("bp%d: bpIntEnable bad interrupt type: %d\n", unit, bs->bs_intType); status = ERROR; break; } return (status); }/********************************************************************************* bpIntGen - interrupt another CPU*/LOCAL void bpIntGen ( FAST CPU_DESC *pCpu, /* ptr to descriptor of CPU to interrupt */ int srcProcNum /* our procNum on this network */ ) { char *pMailbox; int intType; /* if we're trying to interrupt ourself (a bad idea on some CPUs (is20)) * simply invoke the interrupt handler */ if (BP_NTOHL(pCpu->cd_cpuNum) == srcProcNum) { /* read input ring */#ifdef UNIX bpReadAll (pCpu->cd_unit);#else /* UNIX */ (void) netJobAdd ((FUNCPTR)bpReadAll, pCpu->cd_unit, 0,0,0,0);#endif /* UNIX */ return; } switch (intType = BP_NTOHL(pCpu->cd_intType)) { case BP_INT_NONE: /* no interrupt (CPU is polling) */ break; case BP_INT_MAILBOX_1: case BP_INT_MAILBOX_R1: /* interrupt by mailbox (read/write to bus address):
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -