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 + -
显示快捷键?