network.c

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

C
1,061
字号
/* * RTEMS driver for M68360 SCC1 Ethernet * * W. Eric Norum * Saskatchewan Accelerator Laboratory * University of Saskatchewan * Saskatoon, Saskatchewan, CANADA * eric@skatter.usask.ca * *  $Id: network.c,v 1.13 2000/08/02 21:08:44 joel Exp $ */#include <bsp.h>#include <m68360.h>#include <stdio.h>#include <rtems/error.h>#include <rtems/rtems_bsdnet.h>#include <sys/param.h>#include <sys/mbuf.h>#include <sys/socket.h>#include <sys/sockio.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/if_ether.h>/* * Number of SCCs supported by this driver */#define NSCCDRIVER	1/* * Default number of buffer descriptors set aside for this driver. * The number of transmit buffer descriptors has to be quite large * since a single frame often uses four or more buffer descriptors. */#define RX_BUF_COUNT     15#define TX_BUF_COUNT     4#define TX_BD_PER_BUF    4/* * RTEMS event used by interrupt handler to signal driver tasks. * This must not be any of the events used by the network task synchronization. */#define INTERRUPT_EVENT	RTEMS_EVENT_1/* * RTEMS event used to start transmit daemon. * This must not be the same as INTERRUPT_EVENT. */#define START_TRANSMIT_EVENT	RTEMS_EVENT_2/* * Receive buffer size -- Allow for a full ethernet packet including CRC */#define RBUF_SIZE	1520#if (MCLBYTES < RBUF_SIZE)# error "Driver must have MCLBYTES > RBUF_SIZE"#endif/* * Per-device data */struct scc_softc {	struct arpcom		arpcom;	struct mbuf		**rxMbuf;	struct mbuf		**txMbuf;	int			acceptBroadcast;	int			rxBdCount;	int			txBdCount;	int			txBdHead;	int			txBdTail;	int			txBdActiveCount;	m360BufferDescriptor_t	*rxBdBase;	m360BufferDescriptor_t	*txBdBase;	rtems_id		rxDaemonTid;	rtems_id		txDaemonTid;	/*	 * Statistics	 */	unsigned long	rxInterrupts;	unsigned long	rxNotFirst;	unsigned long	rxNotLast;	unsigned long	rxGiant;	unsigned long	rxNonOctet;	unsigned long	rxRunt;	unsigned long	rxBadCRC;	unsigned long	rxOverrun;	unsigned long	rxCollision;	unsigned long	txInterrupts;	unsigned long	txDeferred;	unsigned long	txHeartbeat;	unsigned long	txLateCollision;	unsigned long	txRetryLimit;	unsigned long	txUnderrun;	unsigned long	txLostCarrier;	unsigned long	txRawWait;	unsigned long	txCoalesced;	unsigned long	txCoalesceFailed;	unsigned long	txRetry;};static struct scc_softc scc_softc[NSCCDRIVER];/* * SCC1 interrupt handler */static rtems_isrm360Enet_interrupt_handler (rtems_vector_number v){	/*	 * Frame received?	 */	if ((m360.scc1.sccm & 0x8) && (m360.scc1.scce & 0x8)) {		m360.scc1.scce = 0x8;		m360.scc1.sccm &= ~0x8;		scc_softc[0].rxInterrupts++;		rtems_event_send (scc_softc[0].rxDaemonTid, INTERRUPT_EVENT);	}	/*	 * Buffer transmitted or transmitter error?	 */	if ((m360.scc1.sccm & 0x12) && (m360.scc1.scce & 0x12)) {		m360.scc1.scce = 0x12;		m360.scc1.sccm &= ~0x12;		scc_softc[0].txInterrupts++;		rtems_event_send (scc_softc[0].txDaemonTid, INTERRUPT_EVENT);	}	m360.cisr = 1UL << 30;	/* Clear SCC1 interrupt-in-service bit */}/* * Initialize the ethernet hardware */static voidm360Enet_initialize_hardware (struct scc_softc *sc){	int i;	unsigned char *hwaddr;	rtems_status_code status;	rtems_isr_entry old_handler;	/*	 * Configure port A CLK1, CLK2, TXD1 and RXD1 pins	 */	m360.papar |=  0x303;	m360.padir &= ~0x303;	m360.paodr &= ~0x303;		/*	 * Configure port C CTS1* and CD1* pins	 */	m360.pcpar &= ~0x30;	m360.pcdir &= ~0x30;	m360.pcso  |=  0x30;	/*	 * Connect CLK1 and CLK2 to SCC1	 */	m360.sicr &= ~0xFF;	m360.sicr |= (5 << 3) | 4;	/*	 * Allocate mbuf pointers	 */	sc->rxMbuf = malloc (sc->rxBdCount * sizeof *sc->rxMbuf, M_MBUF, M_NOWAIT);	sc->txMbuf = malloc (sc->txBdCount * sizeof *sc->txMbuf, M_MBUF, M_NOWAIT);	if (!sc->rxMbuf || !sc->txMbuf)		rtems_panic ("No memory for mbuf pointers");	/*	 * Set receiver and transmitter buffer descriptor bases	 */	sc->rxBdBase = M360AllocateBufferDescriptors(sc->rxBdCount);	sc->txBdBase = M360AllocateBufferDescriptors(sc->txBdCount);	m360.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m360;	m360.scc1p.tbase = (char *)sc->txBdBase - (char *)&m360;	/*	 * Send "Init parameters" command	 */	M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SCC1);	/*	 * Set receive and transmit function codes	 */	m360.scc1p.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE;	m360.scc1p.tfcr = M360_TFCR_MOT | M360_TFCR_DMA_SPACE;	/*	 * Set maximum receive buffer length	 */	m360.scc1p.mrblr = RBUF_SIZE;	/*	 * Set CRC parameters	 */	m360.scc1p.un.ethernet.c_pres = 0xFFFFFFFF;	m360.scc1p.un.ethernet.c_mask = 0xDEBB20E3;	/*	 * Clear diagnostic counters	 */	m360.scc1p.un.ethernet.crcec = 0;	m360.scc1p.un.ethernet.alec = 0;	m360.scc1p.un.ethernet.disfc = 0;	/*	 * Set pad value	 */	m360.scc1p.un.ethernet.pads = 0x8888;	/*	 * Set retry limit	 */	m360.scc1p.un.ethernet.ret_lim = 15;	/*	 * Set maximum and minimum frame length	 */	m360.scc1p.un.ethernet.mflr = 1518;	m360.scc1p.un.ethernet.minflr = 64;	m360.scc1p.un.ethernet.maxd1 = RBUF_SIZE;	m360.scc1p.un.ethernet.maxd2 = RBUF_SIZE;	/*	 * Clear group address hash table	 */	m360.scc1p.un.ethernet.gaddr1 = 0;	m360.scc1p.un.ethernet.gaddr2 = 0;	m360.scc1p.un.ethernet.gaddr3 = 0;	m360.scc1p.un.ethernet.gaddr4 = 0;	/*	 * Set our physical address	 */	hwaddr = sc->arpcom.ac_enaddr;	m360.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4];	m360.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2];	m360.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0];	/*	 * Aggressive retry	 */	m360.scc1p.un.ethernet.p_per = 0;		/*	 * Clear individual address hash table	 */	m360.scc1p.un.ethernet.iaddr1 = 0;	m360.scc1p.un.ethernet.iaddr2 = 0;	m360.scc1p.un.ethernet.iaddr3 = 0;	m360.scc1p.un.ethernet.iaddr4 = 0;	/*	 * 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;	/*	 * Clear any outstanding events	 */	m360.scc1.scce = 0xFFFF;	/*	 * Set up interrupts	 */	status = rtems_interrupt_catch (m360Enet_interrupt_handler,						(m360.cicr & 0xE0) | 0x1E,						&old_handler);	if (status != RTEMS_SUCCESSFUL)		rtems_panic ("Can't attach M360 SCC1 interrupt handler: %s\n",						rtems_status_text (status));	m360.scc1.sccm = 0;	/* No interrupts unmasked till necessary */	m360.cimr |= (1UL << 30);	/* Enable SCC1 interrupt */	/*	 * Set up General SCC Mode Register	 * Ethernet configuration	 */	m360.scc1.gsmr_h = 0x0;	m360.scc1.gsmr_l = 0x1088000c;	/*	 * Set up data synchronization register	 * Ethernet synchronization pattern	 */	m360.scc1.dsr = 0xd555;	/*	 * Set up protocol-specific mode register	 *	Heartbeat check	 *	No force collision	 *	Discard short frames	 *	Individual address mode	 *	Ethernet CRC	 *	Not promisuous	 *	Ignore/accept broadcast packets as specified	 *	Normal backoff timer	 *	No loopback	 *	No input sample at end of frame	 *	64-byte limit for late collision	 *	Wait 22 bits before looking for start of frame delimiter	 *	Disable full-duplex operation	 */	m360.scc1.psmr = 0x880A | (sc->acceptBroadcast ? 0 : 0x100);	/*	 * Enable the TENA (RTS1*) pin	 */#if (defined (M68360_ATLAS_HSB))	m360.pbpar |= 0x1000;	m360.pbdir |= 0x1000;#else	m360.pcpar |=  0x1;	m360.pcdir &= ~0x1;#endif}/* * 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 voidm360Enet_retire_tx_bd (struct scc_softc *sc){	rtems_unsigned16 status;	int i;	int nRetired;	struct mbuf *m, *n;	int retries = 0;	int saveStatus = 0;	i = sc->txBdTail;	nRetired = 0;	while ((sc->txBdActiveCount != 0)	   &&  (((status = (sc->txBdBase + i)->status) & M360_BD_READY) == 0)) {		/*		 * Check for errors which stop the transmitter.		 */		if (status & (M360_BD_LATE_COLLISION |				M360_BD_RETRY_LIMIT |				M360_BD_UNDERRUN)) {			int j;			if (status & M360_BD_LATE_COLLISION)				sc->txLateCollision++;			if (status & M360_BD_RETRY_LIMIT)				sc->txRetryLimit++;			if (status & M360_BD_UNDERRUN)				sc->txUnderrun++;			/*			 * Reenable buffer descriptors			 */			j = sc->txBdTail;			for (;;) {				status = (sc->txBdBase + j)->status;				if (status & M360_BD_READY)					break;				(sc->txBdBase + j)->status = M360_BD_READY | 					(status & (M360_BD_PAD | 						   M360_BD_WRAP | 						   M360_BD_INTERRUPT | 						   M360_BD_LAST |						   M360_BD_TX_CRC));				if (status & M360_BD_LAST)					break;				if (++j == sc->txBdCount)					j = 0;			}			/*			 * Move transmitter back to the first			 * buffer descriptor in the frame.			 */			m360.scc1p._tbptr = m360.scc1p.tbase + 				sc->txBdTail * sizeof (m360BufferDescriptor_t);			/*			 * Restart the transmitter			 */			M360ExecuteRISC (M360_CR_OP_RESTART_TX | M360_CR_CHAN_SCC1);			continue;		}		saveStatus |= status;		retries += (status >> 2) & 0xF;		nRetired++;		if (status & M360_BD_LAST) {			/*			 * A full frame has been transmitted.			 * Free all the associated buffer descriptors.			 */			if (saveStatus & M360_BD_DEFER)				sc->txDeferred++;			if (saveStatus & M360_BD_HEARTBEAT)				sc->txHeartbeat++;			if (saveStatus & M360_BD_CARRIER_LOST)				sc->txLostCarrier++;			saveStatus = 0;			sc->txRetry += retries;			retries = 0;			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;	}}/* * SCC reader task */static voidscc_rxDaemon (void *arg){	struct scc_softc *sc = (struct scc_softc *)arg;	struct ifnet *ifp = &sc->arpcom.ac_if;	struct mbuf *m;	rtems_unsigned16 status;	volatile m360BufferDescriptor_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 *);		if (++rxBdIndex == sc->rxBdCount) {			rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT | M360_BD_WRAP;			break;		}		rxBd->status = M360_BD_EMPTY | M360_BD_INTERRUPT;	}	/*	 * Input packet handling loop	 */	rxBdIndex = 0;	for (;;) {		rxBd = sc->rxBdBase + rxBdIndex;		/*		 * Wait for packet if there's not one ready		 */		if ((status = rxBd->status) & M360_BD_EMPTY) {			/*			 * Clear old events			 */			m360.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) & M360_BD_EMPTY) {				rtems_interrupt_level level;				rtems_event_set events;				/*				 * Unmask RXF (Full frame received) event				 */				rtems_interrupt_disable (level);				m360.scc1.sccm |= 0x8;				rtems_interrupt_enable (level);				rtems_bsdnet_event_receive (INTERRUPT_EVENT,						RTEMS_WAIT|RTEMS_EVENT_ANY,						RTEMS_NO_TIMEOUT,						&events);			}		}		/*		 * Check that packet is valid		 */		if ((status & (M360_BD_LAST |				M360_BD_FIRST_IN_FRAME |				M360_BD_LONG |				M360_BD_NONALIGNED |				M360_BD_SHORT |				M360_BD_CRC_ERROR |				M360_BD_OVERRUN |				M360_BD_COLLISION)) ==						(M360_BD_LAST |						M360_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);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?