📄 open_eth.c
字号:
/* * RTEMS driver for Opencores Ethernet Controller * * Weakly based on dec21140 rtems driver and open_eth linux driver * Written by Jiri Gaisler, Gaisler Research * * The license and distribution terms for this file may be * found in found in the file LICENSE in this distribution or at * http://www.OARcorp.com/rtems/license.html. * */#include <rtems.h>#define OPEN_ETH_SUPPORTED#include <bsp.h>#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <rtems/error.h>#include <rtems/rtems_bsdnet.h>#include <libchip/open_eth.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>#ifdef malloc#undef malloc#endif#ifdef free#undef free#endif /*#define OPEN_ETH_DEBUG */#ifdef CPU_U32_FIXextern void ipalign(struct mbuf *m);#endif/* message descriptor entry */struct MDTX{ char *buf;};struct MDRX{ struct mbuf *m;};/* * Number of OCs supported by this driver */#define NOCDRIVER 1/* * Receive buffer size -- Allow for a full ethernet packet including CRC */#define RBUF_SIZE 1536#define ET_MINLEN 64 /* minimum message length *//* * 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 /* event to send when tx buffers become available */#define OPEN_ETH_TX_WAIT_EVENT RTEMS_EVENT_3 /* suspend when all TX descriptors exhausted */ /*#define OETH_SUSPEND_NOTXBUF */#if (MCLBYTES < RBUF_SIZE)# error "Driver must have MCLBYTES > RBUF_SIZE"#endif/* * Per-device data */struct open_eth_softc{ struct arpcom arpcom; oeth_regs *regs; int acceptBroadcast; rtems_id rxDaemonTid; rtems_id txDaemonTid; unsigned int tx_ptr; unsigned int rx_ptr; unsigned int txbufs; unsigned int rxbufs; struct MDTX *txdesc; struct MDRX *rxdesc; rtems_vector_number vector; unsigned int en100MHz; /* * Statistics */ unsigned long rxInterrupts; unsigned long rxPackets; unsigned long rxLengthError; unsigned long rxNonOctet; unsigned long rxBadCRC; unsigned long rxOverrun; unsigned long rxMiss; 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;};static struct open_eth_softc oc;/* OPEN_ETH interrupt handler */static rtems_isropen_eth_interrupt_handler (rtems_vector_number v){ unsigned32 status; /* read and clear interrupt cause */ status = oc.regs->int_src; oc.regs->int_src = status; /* Frame received? */ if (status & (OETH_INT_RXF | OETH_INT_RXE)) { oc.rxInterrupts++; rtems_event_send (oc.rxDaemonTid, INTERRUPT_EVENT); }#ifdef OETH_SUSPEND_NOTXBUF if (status & (OETH_INT_MASK_TXB | OETH_INT_MASK_TXC | OETH_INT_MASK_TXE)) { oc.txInterrupts++; rtems_event_send (oc.txDaemonTid, OPEN_ETH_TX_WAIT_EVENT); }#endif /*#ifdef __leon__ LEON_Clear_interrupt(v-0x10);#endif */}static unsigned32 read_mii(unsigned32 addr){ while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {} oc.regs->miiaddress = addr << 8; oc.regs->miicommand = OETH_MIICOMMAND_RSTAT; while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {} if (!(oc.regs->miistatus & OETH_MIISTATUS_NVALID)) return(oc.regs->miirx_data); else { printf("open_eth: failed to read mii\n"); return (0); }}static void write_mii(unsigned32 addr, unsigned32 data){ while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {} oc.regs->miiaddress = addr << 8; oc.regs->miitx_data = data; oc.regs->miicommand = OETH_MIICOMMAND_WCTRLDATA; while (oc.regs->miistatus & OETH_MIISTATUS_BUSY) {}}/* * Initialize the ethernet hardware */static voidopen_eth_initialize_hardware (struct open_eth_softc *sc){ struct mbuf *m; int i; int mii_cr = 0; oeth_regs *regs; regs = sc->regs; /* Reset the controller. */ regs->ctrlmoder = 0; regs->moder = OETH_MODER_RST; /* Reset ON */ regs->moder = 0; /* Reset OFF */ /* reset PHY and wait for complettion */ /* */ mii_cr = 0x3300; if (!sc->en100MHz) mii_cr = 0; write_mii(0, mii_cr | 0x8000); while (read_mii(0) & 0x8000) {} if (!sc->en100MHz) write_mii(0, 0); mii_cr = read_mii(0); printf("open_eth: driver attached, PHY config : 0x%04x\n", read_mii(0));#ifdef OPEN_ETH_DEBUG printf("mii_cr: %04x\n", mii_cr); for (i=0;i<21;i++) printf("mii_reg %2d : 0x%04x\n", i, read_mii(i));#endif /* Setting TXBD base to sc->txbufs */ regs->tx_bd_num = sc->txbufs; /* Initialize rx/tx pointers. */ sc->rx_ptr = 0; sc->tx_ptr = 0; /* Set min/max packet length */ regs->packet_len = 0x00400600; /* Set IPGT register to recomended value */ regs->ipgt = 0x00000015; /* Set IPGR1 register to recomended value */ regs->ipgr1 = 0x0000000c; /* Set IPGR2 register to recomended value */ regs->ipgr2 = 0x00000012; /* Set COLLCONF register to recomended value */ regs->collconf = 0x000f003f; /* initialize TX descriptors */ sc->txdesc = calloc(sc->txbufs, sizeof(*sc->txdesc)); for (i = 0; i < sc->txbufs; i++) { sc->regs->xd[i].len_status = OETH_TX_BD_PAD | OETH_TX_BD_CRC; sc->txdesc[i].buf = calloc(1, OETH_MAXBUF_LEN);#ifdef OPEN_ETH_DEBUG printf("TXBUF: %08x\n", (int) sc->txdesc[i].buf);#endif } sc->regs->xd[sc->txbufs - 1].len_status |= OETH_TX_BD_WRAP; /* allocate RX buffers */ sc->rxdesc = calloc(sc->rxbufs, sizeof(*sc->rxdesc)); for (i = 0; i < sc->rxbufs; i++) { MGETHDR (m, M_WAIT, MT_DATA); MCLGET (m, M_WAIT); m->m_pkthdr.rcvif = &sc->arpcom.ac_if; sc->rxdesc[i].m = m; sc->regs->xd[i + sc->txbufs].addr = mtod (m, unsigned32 *); sc->regs->xd[i + sc->txbufs].len_status = OETH_RX_BD_EMPTY | OETH_RX_BD_IRQ;#ifdef OPEN_ETH_DEBUG printf("RXBUF: %08x\n", (int) sc->rxdesc[i].m);#endif } sc->regs->xd[sc->rxbufs + sc->txbufs - 1].len_status |= OETH_RX_BD_WRAP; /* set ethernet address. */ regs->mac_addr1 = sc->arpcom.ac_enaddr[0] << 8 | sc->arpcom.ac_enaddr[1]; regs->mac_addr0 = sc->arpcom.ac_enaddr[2] << 24 | sc->arpcom.ac_enaddr[3] << 16 | sc->arpcom.ac_enaddr[4] << 8 | sc->arpcom.ac_enaddr[5]; /* install interrupt vector */ set_vector (open_eth_interrupt_handler, sc->vector, 1); /* clear all pending interrupts */ regs->int_src = 0xffffffff; /* MAC mode register: PAD, IFG, CRCEN */ regs->moder = OETH_MODER_PAD | OETH_MODER_CRCEN | ((mii_cr & 0x100) << 2); /* enable interrupts */ regs->int_mask = OETH_INT_MASK_RXF | OETH_INT_MASK_RXE | OETH_INT_MASK_RXC;#ifdef OETH_SUSPEND_NOTXBUF regs->int_mask |= OETH_INT_MASK_TXB | OETH_INT_MASK_TXC | OETH_INT_MASK_TXE | OETH_INT_BUSY;*/ sc->regs->xd[(sc->txbufs - 1)/2].len_status |= OETH_TX_BD_IRQ; sc->regs->xd[sc->txbufs - 1].len_status |= OETH_TX_BD_IRQ;#endif regs->moder |= OETH_MODER_RXEN | OETH_MODER_TXEN;}static voidopen_eth_rxDaemon (void *arg){ struct ether_header *eh; struct open_eth_softc *dp = (struct open_eth_softc *) &oc; struct ifnet *ifp = &dp->arpcom.ac_if; struct mbuf *m; unsigned int len, len_status, bad; rtems_event_set events; for (;;) { rtems_bsdnet_event_receive (INTERRUPT_EVENT, RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events);#ifdef OPEN_ETH_DEBUG printf ("r\n");#endif while (! ((len_status = dp->regs->xd[dp->rx_ptr+dp->txbufs].len_status) & OETH_RX_BD_EMPTY)) { bad = 0; if (len_status & (OETH_RX_BD_TOOLONG | OETH_RX_BD_SHORT)) { dp->rxLengthError++; bad = 1; } if (len_status & OETH_RX_BD_DRIBBLE) { dp->rxNonOctet++; bad = 1; } if (len_status & OETH_RX_BD_CRCERR) { dp->rxBadCRC++; bad = 1; } if (len_status & OETH_RX_BD_OVERRUN) { dp->rxOverrun++; bad = 1; } if (len_status & OETH_RX_BD_MISS)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -