📄 network.c
字号:
* Set up receive buffer descriptors */ for (i = 0 ; i < sc->rxBdCount ; i++) (sc->rxBdBase + i)->status = 0; /* * Set up transmit buffer descriptors */ for (i = 0 ; i < sc->txBdCount ; i++) { (sc->txBdBase + i)->status = 0; sc->txMbuf[i] = NULL; } sc->txBdHead = sc->txBdTail = 0; sc->txBdActiveCount = 0; /* * Mask all FEC interrupts and clear events */ m8xx.fec.imask = M8xx_FEC_IEVENT_TFINT | M8xx_FEC_IEVENT_RFINT; m8xx.fec.ievent = ~0; /* * Set up interrupts */ if (!BSP_install_rtems_irq_handler (ðernetFECIrqData)) rtems_panic ("Can't attach M860 FEC interrupt handler\n", 0);}/* * Soak up buffer descriptors that have been sent * Note that a buffer descriptor can't be retired as soon as it becomes * ready. The MC68360 Errata (May 96) says that, "If an Ethernet frame is * made up of multiple buffers, the user should not reuse the first buffer * descriptor until the last buffer descriptor of the frame has had its * ready bit cleared by the CPM". */static voidm860Enet_retire_tx_bd (struct m860_enet_struct *sc){ rtems_unsigned16 status; int i; int nRetired; struct mbuf *m, *n; i = sc->txBdTail; nRetired = 0; while ((sc->txBdActiveCount != 0) && (((status = (sc->txBdBase + i)->status) & M8xx_BD_READY) == 0)) { /* * See if anything went wrong */ if (status & (M8xx_BD_DEFER | M8xx_BD_HEARTBEAT | M8xx_BD_LATE_COLLISION | M8xx_BD_RETRY_LIMIT | M8xx_BD_UNDERRUN | M8xx_BD_CARRIER_LOST)) { /* * Check for errors which stop the transmitter. */ if (status & (M8xx_BD_LATE_COLLISION | M8xx_BD_RETRY_LIMIT | M8xx_BD_UNDERRUN)) { if (status & M8xx_BD_LATE_COLLISION) enet_driver[0].txLateCollision++; if (status & M8xx_BD_RETRY_LIMIT) enet_driver[0].txRetryLimit++; if (status & M8xx_BD_UNDERRUN) enet_driver[0].txUnderrun++; /* * Restart the transmitter */ /* FIXME: this should get executed only if using the SCC */ m8xx_cp_execute_cmd (M8xx_CR_OP_RESTART_TX | M8xx_CR_CHAN_SCC1); } if (status & M8xx_BD_DEFER) enet_driver[0].txDeferred++; if (status & M8xx_BD_HEARTBEAT) enet_driver[0].txHeartbeat++; if (status & M8xx_BD_CARRIER_LOST) enet_driver[0].txLostCarrier++; } nRetired++; if (status & M8xx_BD_LAST) { /* * A full frame has been transmitted. * Free all the associated buffer descriptors. */ sc->txBdActiveCount -= nRetired; while (nRetired) { nRetired--; m = sc->txMbuf[sc->txBdTail]; MFREE (m, n); if (++sc->txBdTail == sc->txBdCount) sc->txBdTail = 0; } } if (++i == sc->txBdCount) i = 0; }}/* * reader task */static voidscc_rxDaemon (void *arg){ struct m860_enet_struct *sc = (struct m860_enet_struct *)arg; struct ifnet *ifp = &sc->arpcom.ac_if; struct mbuf *m; rtems_unsigned16 status; m8xxBufferDescriptor_t *rxBd; int rxBdIndex; /* * Allocate space for incoming packets and start reception */ for (rxBdIndex = 0 ; ;) { rxBd = sc->rxBdBase + rxBdIndex; MGETHDR (m, M_WAIT, MT_DATA); MCLGET (m, M_WAIT); m->m_pkthdr.rcvif = ifp; sc->rxMbuf[rxBdIndex] = m; rxBd->buffer = mtod (m, void *); rxBd->status = M8xx_BD_EMPTY | M8xx_BD_INTERRUPT; if (++rxBdIndex == sc->rxBdCount) { rxBd->status |= M8xx_BD_WRAP; break; } } /* * Input packet handling loop */ rxBdIndex = 0; for (;;) { rxBd = sc->rxBdBase + rxBdIndex; /* * Wait for packet if there's not one ready */ if ((status = rxBd->status) & M8xx_BD_EMPTY) { /* * Clear old events */ m8xx.scc1.scce = 0x8; /* * Wait for packet * Note that the buffer descriptor is checked * *before* the event wait -- this catches the * possibility that a packet arrived between the * `if' above, and the clearing of the event register. */ while ((status = rxBd->status) & M8xx_BD_EMPTY) { rtems_event_set events; /* * Unmask RXF (Full frame received) event */ m8xx.scc1.sccm |= 0x8; rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT|RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); } } /* * Check that packet is valid */ if ((status & (M8xx_BD_LAST | M8xx_BD_FIRST_IN_FRAME | M8xx_BD_LONG | M8xx_BD_NONALIGNED | M8xx_BD_SHORT | M8xx_BD_CRC_ERROR | M8xx_BD_OVERRUN | M8xx_BD_COLLISION)) == (M8xx_BD_LAST | M8xx_BD_FIRST_IN_FRAME)) { /* * Pass the packet up the chain. * FIXME: Packet filtering hook could be done here. */ struct ether_header *eh; m = sc->rxMbuf[rxBdIndex]; m->m_len = m->m_pkthdr.len = rxBd->length - sizeof(rtems_unsigned32) - sizeof(struct ether_header); eh = mtod (m, struct ether_header *); m->m_data += sizeof(struct ether_header); ether_input (ifp, eh, m); /* * Allocate a new mbuf */ MGETHDR (m, M_WAIT, MT_DATA); MCLGET (m, M_WAIT); m->m_pkthdr.rcvif = ifp; sc->rxMbuf[rxBdIndex] = m; rxBd->buffer = mtod (m, void *); } else { /* * Something went wrong with the reception */ if (!(status & M8xx_BD_LAST)) sc->rxNotLast++; if (!(status & M8xx_BD_FIRST_IN_FRAME)) sc->rxNotFirst++; if (status & M8xx_BD_LONG) sc->rxGiant++; if (status & M8xx_BD_NONALIGNED) sc->rxNonOctet++; if (status & M8xx_BD_SHORT) sc->rxRunt++; if (status & M8xx_BD_CRC_ERROR) sc->rxBadCRC++; if (status & M8xx_BD_OVERRUN) sc->rxOverrun++; if (status & M8xx_BD_COLLISION) sc->rxCollision++; } /* * Reenable the buffer descriptor */ rxBd->status = (status & (M8xx_BD_WRAP | M8xx_BD_INTERRUPT)) | M8xx_BD_EMPTY; /* * Move to next buffer descriptor */ if (++rxBdIndex == sc->rxBdCount) rxBdIndex = 0; }}static voidfec_rxDaemon (void *arg){ struct m860_enet_struct *sc = (struct m860_enet_struct *)arg; struct ifnet *ifp = &sc->arpcom.ac_if; struct mbuf *m; rtems_unsigned16 status; m8xxBufferDescriptor_t *rxBd; int rxBdIndex; /* * Allocate space for incoming packets and start reception */ for (rxBdIndex = 0 ; ;) { rxBd = sc->rxBdBase + rxBdIndex; MGETHDR (m, M_WAIT, MT_DATA); MCLGET (m, M_WAIT); m->m_pkthdr.rcvif = ifp; sc->rxMbuf[rxBdIndex] = m; rxBd->buffer = mtod (m, void *); rxBd->status = M8xx_BD_EMPTY; m8xx.fec.r_des_active = 0x1000000; if (++rxBdIndex == sc->rxBdCount) { rxBd->status |= M8xx_BD_WRAP; break; } } /* * Input packet handling loop */ rxBdIndex = 0; for (;;) { rxBd = sc->rxBdBase + rxBdIndex; /* * Wait for packet if there's not one ready */ if ((status = rxBd->status) & M8xx_BD_EMPTY) { /* * Clear old events */ m8xx.fec.ievent = M8xx_FEC_IEVENT_RFINT; /* * Wait for packet * Note that the buffer descriptor is checked * *before* the event wait -- this catches the * possibility that a packet arrived between the * `if' above, and the clearing of the event register. */ while ((status = rxBd->status) & M8xx_BD_EMPTY) { rtems_event_set events; /* * Unmask RXF (Full frame received) event */ m8xx.fec.ievent |= M8xx_FEC_IEVENT_RFINT; rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT|RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); } } /* * Check that packet is valid */ if (status & M8xx_BD_LAST) { /* * Pass the packet up the chain. * FIXME: Packet filtering hook could be done here. */ struct ether_header *eh; m = sc->rxMbuf[rxBdIndex]; m->m_len = m->m_pkthdr.len = rxBd->length - sizeof(rtems_unsigned32) - sizeof(struct ether_header); eh = mtod (m, struct ether_header *); m->m_data += sizeof(struct ether_header); ether_input (ifp, eh, m); /* * Allocate a new mbuf */ MGETHDR (m, M_WAIT, MT_DATA); MCLGET (m, M_WAIT); m->m_pkthdr.rcvif = ifp; sc->rxMbuf[rxBdIndex] = m; rxBd->buffer = mtod (m, void *); } else { /* * Something went wrong with the reception */ if (!(status & M8xx_BD_LAST)) sc->rxNotLast++; if (status & M8xx_BD_LONG) sc->rxGiant++; if (status & M8xx_BD_NONALIGNED) sc->rxNonOctet++; if (status & M8xx_BD_SHORT) sc->rxRunt++; if (status & M8xx_BD_CRC_ERROR) sc->rxBadCRC++; if (status & M8xx_BD_OVERRUN) sc->rxOverrun++; if (status & M8xx_BD_COLLISION) sc->rxCollision++; } /* * Reenable the buffer descriptor */ rxBd->status = (status & M8xx_BD_WRAP) | M8xx_BD_EMPTY; m8xx.fec.r_des_active = 0x1000000; /* * Move to next buffer descriptor */ if (++rxBdIndex == sc->rxBdCount) rxBdIndex = 0; }}static voidscc_sendpacket (struct ifnet *ifp, struct mbuf *m){ struct m860_enet_struct *sc = ifp->if_softc; volatile m8xxBufferDescriptor_t *firstTxBd, *txBd; struct mbuf *l = NULL; rtems_unsigned16 status; int nAdded; /* * Free up buffer descriptors */ m860Enet_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. */ nAdded = 0; txBd = firstTxBd = sc->txBdBase + sc->txBdHead; for (;;) { /* * Wait for buffer descriptor to become available. */ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { /* * Clear old events */ m8xx.scc1.scce = 0x12; /* * 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. */ m860Enet_retire_tx_bd (sc); while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { rtems_event_set events; /* * Unmask TXB (buffer transmitted) and * TXE (transmitter error) events. */ m8xx.scc1.sccm |= 0x12; rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT|RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); m860Enet_retire_tx_bd (sc); } } /* * Don't set the READY flag till the * whole packet has been readied. */ status = nAdded ? M8xx_BD_READY : 0; /* * FIXME: Why not deal with empty mbufs at at higher level? * The IP fragmentation routine in ip_output * can produce packet fragments with zero length. * I think that ip_output should be changed to get * rid of these zero-length mbufs, but for now, * I'll deal with them here. */ if (m->m_len) { /* * Fill in the buffer descriptor */ txBd->buffer = mtod (m, void *); txBd->length = m->m_len; sc->txMbuf[sc->txBdHead] = m; nAdded++; if (++sc->txBdHead == sc->txBdCount) { status |= M8xx_BD_WRAP; sc->txBdHead = 0; } l = m; m = m->m_next; } else { /* * Just toss empty mbufs */ struct mbuf *n; MFREE (m, n); m = n; if (l != NULL) l->m_next = m; } /* * Set the transmit buffer status. * Break out of the loop if this mbuf is the last in the frame. */ if (m == NULL) { if (nAdded) { status |= M8xx_BD_PAD | M8xx_BD_LAST | M8xx_BD_TX_CRC | M8xx_BD_INTERRUPT; txBd->status = status; firstTxBd->status |= M8xx_BD_READY; sc->txBdActiveCount += nAdded; } break; } txBd->status = status; txBd = sc->txBdBase + sc->txBdHead; }}static voidfec_sendpacket (struct ifnet *ifp, struct mbuf *m){ struct m860_enet_struct *sc = ifp->if_softc; volatile m8xxBufferDescriptor_t *firstTxBd, *txBd; /* struct mbuf *l = NULL; */ rtems_unsigned16 status; int nAdded; /* * Free up buffer descriptors */ m860Enet_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. */ nAdded = 0; txBd = firstTxBd = sc->txBdBase + sc->txBdHead; for (;;) { /* * Wait for buffer descriptor to become available. */ if ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { /* * Clear old events */ m8xx.fec.ievent = M8xx_FEC_IEVENT_TFINT; /* * 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. */ m860Enet_retire_tx_bd (sc); while ((sc->txBdActiveCount + nAdded) == sc->txBdCount) { rtems_event_set events;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -