📄 network.c
字号:
else { /* * Something went wrong with the reception */ if (!(status & BUF_STAT_LAST)) sc->rxNotLast++; if (!(status & BUF_STAT_FIRST_IN_FRAME)) sc->rxNotFirst++; if (status & BUF_STAT_LONG) sc->rxGiant++; if (status & BUF_STAT_NONALIGNED) sc->rxNonOctet++; if (status & BUF_STAT_SHORT) sc->rxRunt++; if (status & BUF_STAT_CRC_ERROR) sc->rxBadCRC++; if (status & BUF_STAT_OVERRUN) sc->rxOverrun++; if (status & BUF_STAT_COLLISION) sc->rxCollision++; } /* * Reenable the buffer descriptor */ rxBd->stat_ctrl = (status & (BUF_STAT_WRAP | BUF_STAT_INTERRUPT)) | BUF_STAT_EMPTY; /* * Move to next buffer descriptor */ if (++rxBdIndex == sc->rxBdCount) rxBdIndex = 0; }}static voidsendpacket (struct ifnet *ifp, struct mbuf *m){ struct scc_softc *sc = ifp->if_softc; volatile struct m68302_scc_bd *firstTxBd, *txBd; struct mbuf *l = NULL; rtems_unsigned16 status; int nAdded; /* * Free up buffer descriptors */ m302Enet_retire_tx_bd (sc); /* * Set up the transmit buffer descriptors. * No need to pad out short packets since the * hardware takes care of that automatically. * No need to copy the packet to a contiguous buffer * since the hardware is capable of scatter/gather DMA. */ status = 0; nAdded = 0; txBd = firstTxBd = sc->txBdBase + sc->txBdHead; while (m) { /* * There are more mbufs in the packet than there * are transmit buffer descriptors. * Coalesce into a single buffer. */ if (nAdded == sc->txBdCount) { struct mbuf *nm; int j; char *dest; /* * Get the pointer to the first mbuf of the packet */ if (sc->txBdTail != sc->txBdHead) rtems_panic ("sendpacket coalesce"); m = sc->txMbuf[sc->txBdTail]; /* * Rescind the buffer descriptor READY bits */ for (j = 0 ; j < sc->txBdCount ; j++) (sc->txBdBase + j)->stat_ctrl = 0; /* * Allocate an mbuf cluster * Toss the packet if allocation fails */ MGETHDR (nm, M_DONTWAIT, MT_DATA); if (nm == NULL) { sc->txCoalesceFailed++; m_freem (m);
return; } MCLGET (nm, M_DONTWAIT); if (nm->m_ext.ext_buf == NULL) { sc->txCoalesceFailed++; m_freem (m); m_free (nm);
return; } nm->m_pkthdr = m->m_pkthdr; nm->m_len = nm->m_pkthdr.len; /* * Copy data from packet chain to mbuf cluster */ sc->txCoalesced++; dest = nm->m_ext.ext_buf; while (m) { struct mbuf *n; if (m->m_len) { memcpy (dest, mtod(m, caddr_t), m->m_len); dest += m->m_len; } MFREE (m, n); m = n; } /* * Redo the send with the new mbuf cluster */ m = nm; nAdded = 0; status = 0; continue; } /* * Wait for buffer descriptor to become available. */ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { /* * Clear old events */ M68en302imp_intr_event = INTR_EVENT_BIT_TFINT | INTR_EVENT_BIT_TXB; /* * Wait for buffer descriptor to become available. * Note that the buffer descriptors are checked * *before* entering the wait loop -- this catches * the possibility that a buffer descriptor became * available between the `if' above, and the clearing * of the event register. * This is to catch the case where the transmitter * stops in the middle of a frame -- and only the * last buffer descriptor in a frame can generate * an interrupt. */ m302Enet_retire_tx_bd (sc); while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { rtems_interrupt_level level; rtems_event_set events; /* * Unmask TXB (buffer transmitted) and * TXE (transmitter error) events. */ rtems_interrupt_disable (level); M68en302imp_intr_mask |= INTR_MASK_BIT_TFIEN | INTR_MASK_BIT_TXIEN; rtems_interrupt_enable (level);
rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT|RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); m302Enet_retire_tx_bd (sc); } } /* * The IP fragmentation routine in ip_output * can produce packet fragments with zero length. */ if (m->m_len) { /* * Fill in the buffer descriptor. * Don't set the READY flag in the first buffer * descriptor till the whole packet has been readied. */ txBd = sc->txBdBase + sc->txBdHead; txBd->p_buffer = mtod (m, void *); txBd->data_lgth = m->m_len; sc->txMbuf[sc->txBdHead] = m; status = nAdded ? BUF_STAT_READY : 0; if (++sc->txBdHead == sc->txBdCount) { status |= BUF_STAT_WRAP; sc->txBdHead = 0; } txBd->stat_ctrl = status; l = m; m = m->m_next; nAdded++; } else { /* * Just toss empty mbufs */ struct mbuf *n; MFREE (m, n); m = n; if (l != NULL) l->m_next = m; } } if (nAdded) { /* * Send the packet */ txBd->stat_ctrl = status | BUF_STAT_LAST | BUF_STAT_TX_CRC | BUF_STAT_INTERRUPT; firstTxBd->stat_ctrl |= BUF_STAT_READY; sc->txBdActiveCount += nAdded; }}/* * Driver transmit daemon */voidscc_txDaemon (void *arg){ struct scc_softc *sc = (struct scc_softc *)arg; struct ifnet *ifp = &sc->arpcom.ac_if; struct mbuf *m; rtems_event_set events; for (;;) { /* * Wait for packet */ rtems_bsdnet_event_receive (START_TRANSMIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); /* * Send packets till queue is empty */ for (;;) { /* * Get the next mbuf chain to transmit. */ IF_DEQUEUE(&ifp->if_snd, m); if (!m) break; sendpacket (ifp, m); } ifp->if_flags &= ~IFF_OACTIVE; }}/* * Send packet (caller provides header). */static voidscc_start (struct ifnet *ifp){ struct scc_softc *sc = ifp->if_softc; rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); ifp->if_flags |= IFF_OACTIVE;}
/* * Initialize and start the device */static voidscc_init (void *arg){ struct scc_softc *sc = arg; struct ifnet *ifp = &sc->arpcom.ac_if; if (sc->txDaemonTid == 0) { /* * Set up SCC hardware */ m302Enet_initialize_hardware (sc);
sc->txDaemonTid = rtems_bsdnet_newproc ("SCtx", 4096, scc_txDaemon, sc); sc->rxDaemonTid = rtems_bsdnet_newproc ("SCrx", 4096, scc_rxDaemon, sc); } /* * Set flags appropriately *//* if (ifp->if_flags & IFF_PROMISC) m360.scc1.psmr |= 0x200; else m360.scc1.psmr &= ~0x200;*/ /* * Tell the world that we're running. */ ifp->if_flags |= IFF_RUNNING; /* * Enable receiver and transmitter */ M68en302imp_ecntrl = ECNTRL_BIT_RESET | ECNTRL_BIT_ETHER_EN; }/* * Stop the device */static voidscc_stop (struct scc_softc *sc){ struct ifnet *ifp = &sc->arpcom.ac_if; ifp->if_flags &= ~IFF_RUNNING; /* * Shut down receiver and transmitter */ M68en302imp_ecntrl &= ~(ECNTRL_BIT_RESET | ECNTRL_BIT_ETHER_EN);}/* * Show interface statistics */static voidscc_stats (struct scc_softc *sc){ printf (" Rx Interrupts:%-8lu", sc->rxInterrupts); printf (" Not First:%-8lu", sc->rxNotFirst); printf (" Not Last:%-8lu\r\n", sc->rxNotLast); printf (" Giant:%-8lu", sc->rxGiant); printf (" Runt:%-8lu", sc->rxRunt); printf (" Non-octet:%-8lu\r\n", sc->rxNonOctet); printf (" Bad CRC:%-8lu", sc->rxBadCRC); printf (" Overrun:%-8lu", sc->rxOverrun); printf (" Collision:%-8lu\r\n", sc->rxCollision);/* printf (" Discarded:%-8lu\r\n", (unsigned long)m360.scc1p.un.ethernet.disfc);*/ printf (" Tx Interrupts:%-8lu", sc->txInterrupts); printf (" Deferred:%-8lu", sc->txDeferred); printf (" Missed Hearbeat:%-8lu\r\n", sc->txHeartbeat); printf (" No Carrier:%-8lu", sc->txLostCarrier); printf ("Retransmit Limit:%-8lu", sc->txRetryLimit); printf (" Late Collision:%-8lu\r\n", sc->txLateCollision); printf (" Underrun:%-8lu", sc->txUnderrun); printf (" Raw output wait:%-8lu", sc->txRawWait); printf (" Coalesced:%-8lu\r\n", sc->txCoalesced); printf (" Coalesce failed:%-8lu", sc->txCoalesceFailed); printf (" Retries:%-8lu\r\n", sc->txRetry);}/* * Driver ioctl handler */static intscc_ioctl (struct ifnet *ifp, int command, caddr_t data){ struct scc_softc *sc = ifp->if_softc; int error = 0; switch (command) { case SIOCGIFADDR: case SIOCSIFADDR: ether_ioctl (ifp, command, data); break; case SIOCSIFFLAGS: switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) { case IFF_RUNNING: scc_stop (sc); break; case IFF_UP: scc_init (sc); break; case IFF_UP | IFF_RUNNING: scc_stop (sc); scc_init (sc); break; default: break; } break; case SIO_RTEMS_SHOW_STATS: scc_stats (sc); break; /* * FIXME: All sorts of multicast commands need to be added here! */ default: error = EINVAL; break; } return error;}/* * Attach an SCC driver to the system */intrtems_ether1_driver_attach (struct rtems_bsdnet_ifconfig *config){ struct scc_softc *sc; struct ifnet *ifp; int mtu; int unitNumber; char *unitName; a_m68302_imp = (struct m68302_imp *)0x700000L; /* * Parse driver name */ if ((unitNumber = rtems_bsdnet_parse_driver_name (config, &unitName)) < 0) return 0; /* * Is driver free? */ if ((unitNumber <= 0) || (unitNumber > NSCCDRIVER)) { printf ("Bad SCC unit number.\r\n"); return 0; } sc = &scc_softc[unitNumber - 1]; ifp = &sc->arpcom.ac_if; if (ifp->if_softc != NULL) { printf ("Driver already in use.\r\n"); return 0; } /* * Process options */ if (config->hardware_address) { memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); } if (config->mtu) mtu = config->mtu; else mtu = ETHERMTU; if (config->rbuf_count) sc->rxBdCount = config->rbuf_count; else sc->rxBdCount = RX_BUF_COUNT; if (config->xbuf_count) sc->txBdCount = config->xbuf_count; else sc->txBdCount = TX_BUF_COUNT; sc->acceptBroadcast = !config->ignore_broadcast; /* * Set up network interface values */ ifp->if_softc = sc; ifp->if_unit = unitNumber; ifp->if_name = unitName; ifp->if_mtu = mtu; ifp->if_init = scc_init; ifp->if_ioctl = scc_ioctl; ifp->if_start = scc_start; ifp->if_output = ether_output; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; if (ifp->if_snd.ifq_maxlen == 0) ifp->if_snd.ifq_maxlen = ifqmaxlen; /* * Attach the interface */ if_attach (ifp); ether_ifattach (ifp); return 1;};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -