network.c

来自「RTEMS (Real-Time Executive for Multiproc」· C语言 代码 · 共 1,061 行 · 第 1/2 页

C
1,061
字号
			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 & M360_BD_LAST))				sc->rxNotLast++;			if (!(status & M360_BD_FIRST_IN_FRAME))				sc->rxNotFirst++;			if (status & M360_BD_LONG)				sc->rxGiant++;			if (status & M360_BD_NONALIGNED)				sc->rxNonOctet++;			if (status & M360_BD_SHORT)				sc->rxRunt++;			if (status & M360_BD_CRC_ERROR)				sc->rxBadCRC++;			if (status & M360_BD_OVERRUN)				sc->rxOverrun++;			if (status & M360_BD_COLLISION)				sc->rxCollision++;		}		/*		 * Reenable the buffer descriptor		 */		rxBd->status = (status & (M360_BD_WRAP | M360_BD_INTERRUPT)) | M360_BD_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 m360BufferDescriptor_t *firstTxBd, *txBd;	struct mbuf *l = NULL;	rtems_unsigned16 status;	int nAdded;	/*	 * Free up buffer descriptors	 */	m360Enet_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)->status = 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			 */			m360.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.			 */			m360Enet_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);				m360.scc1.sccm |= 0x12;				rtems_interrupt_enable (level);				rtems_bsdnet_event_receive (INTERRUPT_EVENT,						RTEMS_WAIT|RTEMS_EVENT_ANY,						RTEMS_NO_TIMEOUT,						&events);				m360Enet_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->buffer = mtod (m, void *);			txBd->length = m->m_len;			sc->txMbuf[sc->txBdHead] = m;			status = nAdded ? M360_BD_READY : 0;			if (++sc->txBdHead == sc->txBdCount) {				status |= M360_BD_WRAP;				sc->txBdHead = 0;			}			txBd->status = 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->status = status | M360_BD_PAD | M360_BD_LAST | M360_BD_TX_CRC | M360_BD_INTERRUPT;		firstTxBd->status |= M360_BD_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		 */		m360Enet_initialize_hardware (sc);		/*		 * Start driver tasks		 */		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	 */	m360.scc1.gsmr_l |= 0x30;}/* * 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	 */	m360.scc1.gsmr_l &= ~0x30;}/* * 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\n", sc->rxNotLast);	printf ("              Giant:%-8lu", sc->rxGiant);	printf ("            Runt:%-8lu", sc->rxRunt);	printf ("       Non-octet:%-8lu\n", sc->rxNonOctet);	printf ("            Bad CRC:%-8lu", sc->rxBadCRC);	printf ("         Overrun:%-8lu", sc->rxOverrun);	printf ("       Collision:%-8lu\n", sc->rxCollision);	printf ("          Discarded:%-8lu\n", (unsigned long)m360.scc1p.un.ethernet.disfc);	printf ("      Tx Interrupts:%-8lu", sc->txInterrupts);	printf ("        Deferred:%-8lu", sc->txDeferred);	printf (" Missed Hearbeat:%-8lu\n", sc->txHeartbeat);	printf ("         No Carrier:%-8lu", sc->txLostCarrier);	printf ("Retransmit Limit:%-8lu", sc->txRetryLimit);	printf ("  Late Collision:%-8lu\n", sc->txLateCollision);	printf ("           Underrun:%-8lu", sc->txUnderrun);	printf (" Raw output wait:%-8lu", sc->txRawWait);	printf ("       Coalesced:%-8lu\n", sc->txCoalesced);	printf ("    Coalesce failed:%-8lu", sc->txCoalesceFailed);	printf ("         Retries:%-8lu\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_scc1_driver_attach (struct rtems_bsdnet_ifconfig *config, int attaching){	struct scc_softc *sc;	struct ifnet *ifp;	int mtu;	int unitNumber;	char *unitName;	/*	 * Make sure we're really being attached	 */	if (!attaching) {		printf ("SCC1 driver can not be detached.\n");		return 0;	}			/* 	 * 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.\n");		return 0;	}	sc = &scc_softc[unitNumber - 1];	ifp = &sc->arpcom.ac_if;	if (ifp->if_softc != NULL) {		printf ("Driver already in use.\n");		return 0;	}	/*	 * Process options	 */	if (config->hardware_address) {		memcpy (sc->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);	}	else {		/*		 * The first 4 bytes of the bootstrap prom		 * contain the value loaded into the stack		 * pointer as part of the CPU32's hardware		 * reset exception handler.  The following		 * 4 bytes contain the value loaded into the		 * program counter.  The boards' Ethernet		 * address is stored in the six bytes		 * immediately preceding this initial		 * program counter value.		 *		 * See start360/start360.s.		 */		extern void *_RomBase;	/* From linkcmds */		const unsigned long *ExceptionVectors;		const unsigned char *entryPoint;		/*		 * Sanity check -- assume entry point must be		 * within 1 MByte of beginning of boot ROM.		 */		ExceptionVectors = (const unsigned long *)&_RomBase;		entryPoint = (const unsigned char *)ExceptionVectors[1];		if (((unsigned long)entryPoint - (unsigned long)ExceptionVectors)					>= (1 * 1024 * 1024)) {			printf ("Warning -- Ethernet address can not be found in bootstrap PROM.\n");			sc->arpcom.ac_enaddr[0] = 0x08;			sc->arpcom.ac_enaddr[1] = 0xF3;			sc->arpcom.ac_enaddr[2] = 0x3E;			sc->arpcom.ac_enaddr[3] = 0xC2;			sc->arpcom.ac_enaddr[4] = 0x7E;			sc->arpcom.ac_enaddr[5] = 0x38;		}		else {			memcpy (sc->arpcom.ac_enaddr, entryPoint - ETHER_ADDR_LEN, 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 * TX_BD_PER_BUF;	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 + =
减小字号Ctrl + -
显示快捷键?