📄 network.c
字号:
/* * RTEMS/TCPIP driver for MPC8xx SCC1 Ethernet * * Modified for MPC860 by Jay Monkman (jmonkman@frasca.com) * * This supports Ethernet on either SCC1 or the FEC of the MPC860T. * Right now, we only do 10 Mbps, even with the FEC. The function * rtems_enet_driver_attach determines which one to use. Currently, * only one may be used at a time. * * Based on the MC68360 network driver by * W. Eric Norum * Saskatchewan Accelerator Laboratory * University of Saskatchewan * Saskatoon, Saskatchewan, CANADA * eric@skatter.usask.ca * * This supports ethernet on SCC1. Right now, we only do 10 Mbps. * * Modifications by Darlene Stewart <Darlene.Stewart@iit.nrc.ca> * and Charles-Antoine Gauthier <charles.gauthier@iit.nrc.ca> * Copyright (c) 1999, National Research Council of Canada * * $Id: network.c,v 1.9 2002/11/04 22:18:26 joel Exp $ */#include <bsp.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>#include <bsp/irq.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>/* * Number of interfaces supported by this driver */#define NIFACES 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 32#define TX_BUF_COUNT 8#define TX_BD_PER_BUF 4#define INET_ADDR_MAX_BUF_SIZE (sizeof "255.255.255.255")/* * RTEMS event used by interrupt handler to signal daemons. * This must *not* be the same event used by the TCP/IP 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 plus CRC (1518). * Round off to nearest multiple of RBUF_ALIGN. */#define MAX_MTU_SIZE 1518#define RBUF_ALIGN 4#define RBUF_SIZE ((MAX_MTU_SIZE + RBUF_ALIGN) & ~RBUF_ALIGN)#if (MCLBYTES < RBUF_SIZE)# error "Driver must have MCLBYTES > RBUF_SIZE"#endif/* * Per-device data */struct m8xx_enet_struct { struct arpcom arpcom; struct mbuf **rxMbuf; struct mbuf **txMbuf; int acceptBroadcast; int rxBdCount; int txBdCount; int txBdHead; int txBdTail; int txBdActiveCount; m8xxBufferDescriptor_t *rxBdBase; m8xxBufferDescriptor_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;};static struct m8xx_enet_struct enet_driver[NIFACES];static void m8xx_scc1_ethernet_on(const rtems_irq_connect_data* ptr){}static void m8xx_scc1_ethernet_off(const rtems_irq_connect_data* ptr){ /* * Please put relevant code there */}static void m8xx_scc1_ethernet_isOn(const rtems_irq_connect_data* ptr){ int BSP_irq_enabled_at_cpm(const rtems_irq_symbolic_name ); BSP_irq_enabled_at_cpm (ptr->name);}/* * SCC1 interrupt handler */static void m8xx_scc1_interrupt_handler (){ /* Frame received? */ if ((m8xx.scc1.sccm & 0x8) && (m8xx.scc1.scce & 0x8)) { m8xx.scc1.scce = 0x8; /* Clear receive frame int */ m8xx.scc1.sccm &= ~0x8; /* Disable receive frame ints */ enet_driver[0].rxInterrupts++; /* Rx int has occurred */ rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT); } /* Buffer transmitted or transmitter error? */ if ((m8xx.scc1.sccm & 0x12) && (m8xx.scc1.scce & 0x12)) { m8xx.scc1.scce = 0x12; /* Clear Tx int */ m8xx.scc1.sccm &= ~0x12; /* Disable Tx ints */ enet_driver[0].txInterrupts++; /* Tx int has occurred */ rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT); }}#ifdef MPC860T/* * FEC interrupt handler */static void m860_fec_interrupt_handler (){ /* * Frame received? */ if (m8xx.fec.ievent & M8xx_FEC_IEVENT_RFINT) { m8xx.fec.ievent = M8xx_FEC_IEVENT_RFINT; enet_driver[0].rxInterrupts++; rtems_event_send (enet_driver[0].rxDaemonTid, INTERRUPT_EVENT); } /* * Buffer transmitted or transmitter error? */ if (m8xx.fec.ievent & M8xx_FEC_IEVENT_TFINT) { m8xx.fec.ievent = M8xx_FEC_IEVENT_TFINT; enet_driver[0].txInterrupts++; rtems_event_send (enet_driver[0].txDaemonTid, INTERRUPT_EVENT); }}#endifstatic rtems_irq_connect_data ethernetSCC1IrqData = { BSP_CPM_IRQ_SCC1, (rtems_irq_hdl) m8xx_scc1_interrupt_handler, (rtems_irq_enable) m8xx_scc1_ethernet_on, (rtems_irq_disable) m8xx_scc1_ethernet_off, (rtems_irq_is_enabled)m8xx_scc1_ethernet_isOn};/* * Initialize the ethernet hardware */static voidm8xx_enet_initialize (struct m8xx_enet_struct *sc){ int i; unsigned char *hwaddr; /* * Configure port A * PA15 is enet RxD. Set PAPAR(15) to 1, PADIR(15) to 0. * PA14 is enet TxD. Set PAPAR(14) to 1, PADIR(14) to 0, PAODR(14) to 0. * PA7 is input CLK1. Set PAPAR(7) to 1, PADIR(7) to 0. * PA6 is input CLK2. Set PAPAR(6) to 1, PADIR(6) to 0. */ m8xx.papar |= 0x303; m8xx.padir &= ~0x303; m8xx.paodr &= ~0x2; /* * Configure port C * PC11 is CTS1*. Set PCPAR(11) to 0, PCDIR(11) to 0, and PCSO(11) to 1. * PC10 is CD1*. Set PCPAR(10) to 0, PCDIR(10) to 0, and PCSO(10) to 1. */ m8xx.pcpar &= ~0x30; m8xx.pcdir &= ~0x30; m8xx.pcso |= 0x30; /* * Connect CLK1 and CLK2 to SCC1 in the SICR. * CLK1 is TxClk, CLK2 is RxClk. No grant mechanism, SCC1 is directly * connected to the NMSI pins. * R1CS = 0b101 (CLK2) * T1CS = 0b100 (CLK1) */ m8xx.sicr |= 0x2C; /* * Initialize SDMA configuration register */ m8xx.sdcr = 1; /* * 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 = m8xx_bd_allocate(sc->rxBdCount); sc->txBdBase = m8xx_bd_allocate(sc->txBdCount); m8xx.scc1p.rbase = (char *)sc->rxBdBase - (char *)&m8xx; m8xx.scc1p.tbase = (char *)sc->txBdBase - (char *)&m8xx; /* * Send "Init parameters" command */ m8xx_cp_execute_cmd (M8xx_CR_OP_INIT_RX_TX | M8xx_CR_CHAN_SCC1); /* * Set receive and transmit function codes */ m8xx.scc1p.rfcr = M8xx_RFCR_MOT | M8xx_RFCR_DMA_SPACE(0); m8xx.scc1p.tfcr = M8xx_TFCR_MOT | M8xx_TFCR_DMA_SPACE(0); /* * Set maximum receive buffer length */ m8xx.scc1p.mrblr = RBUF_SIZE; /* * Set CRC parameters */ m8xx.scc1p.un.ethernet.c_pres = 0xFFFFFFFF; m8xx.scc1p.un.ethernet.c_mask = 0xDEBB20E3; /* * Clear diagnostic counters */ m8xx.scc1p.un.ethernet.crcec = 0; m8xx.scc1p.un.ethernet.alec = 0; m8xx.scc1p.un.ethernet.disfc = 0; /* * Set pad value */ m8xx.scc1p.un.ethernet.pads = 0x8888; /* * Set retry limit */ m8xx.scc1p.un.ethernet.ret_lim = 15; /* * Set maximum and minimum frame length */ m8xx.scc1p.un.ethernet.mflr = 1518; m8xx.scc1p.un.ethernet.minflr = 64; m8xx.scc1p.un.ethernet.maxd1 = MAX_MTU_SIZE; m8xx.scc1p.un.ethernet.maxd2 = MAX_MTU_SIZE; /* * Clear group address hash table */ m8xx.scc1p.un.ethernet.gaddr1 = 0; m8xx.scc1p.un.ethernet.gaddr2 = 0; m8xx.scc1p.un.ethernet.gaddr3 = 0; m8xx.scc1p.un.ethernet.gaddr4 = 0; /* * Set our physical address */ hwaddr = sc->arpcom.ac_enaddr; m8xx.scc1p.un.ethernet.paddr_h = (hwaddr[5] << 8) | hwaddr[4]; m8xx.scc1p.un.ethernet.paddr_m = (hwaddr[3] << 8) | hwaddr[2]; m8xx.scc1p.un.ethernet.paddr_l = (hwaddr[1] << 8) | hwaddr[0]; /* * Aggressive retry */ m8xx.scc1p.un.ethernet.p_per = 0; /* * Clear individual address hash table */ m8xx.scc1p.un.ethernet.iaddr1 = 0; m8xx.scc1p.un.ethernet.iaddr2 = 0; m8xx.scc1p.un.ethernet.iaddr3 = 0; m8xx.scc1p.un.ethernet.iaddr4 = 0; /* * Clear temp address */ m8xx.scc1p.un.ethernet.taddr_l = 0; m8xx.scc1p.un.ethernet.taddr_m = 0; m8xx.scc1p.un.ethernet.taddr_h = 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 */ m8xx.scc1.scce = 0xFFFF; /* * Set up interrupts */ if (!BSP_install_rtems_irq_handler (ðernetSCC1IrqData)) { rtems_panic ("Can't attach M8xx SCC1 interrupt handler\n"); } m8xx.scc1.sccm = 0; /* No interrupts unmasked till necessary */ /* * Set up General SCC Mode Register * Ethernet configuration */ m8xx.scc1.gsmr_h = 0x0; m8xx.scc1.gsmr_l = 0x1088000c; /* * Set up data synchronization register * Ethernet synchronization pattern */ m8xx.scc1.dsr = 0xd555; /* * Set up protocol-specific mode register * No 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 */ m8xx.scc1.psmr = 0x080A | (sc->acceptBroadcast ? 0 : 0x100); /* * Enable the TENA (RTS1*) pin */ m8xx.pcpar |= 0x1; m8xx.pcdir &= ~0x1; /* * Enable receiver and transmitter */ m8xx.scc1.gsmr_l = 0x1088003c;}#ifdef MPC860T/* * Please organize FEC controller code better by moving code from * m860_fec_initialize_hardware to m8xx_fec_ethernet_on */static void m8xx_fec_ethernet_on(){};static void m8xx_fec_ethernet_off(){};static int m8xx_fec_ethernet_isOn (const rtems_irq_connect_data* ptr){ return BSP_irq_enabled_at_siu (ptr->name);}static rtems_irq_connect_data ethernetFECIrqData = { BSP_FAST_ETHERNET_CTRL, (rtems_irq_hdl) m8xx_fec_interrupt_handler, (rtems_irq_enable) m8xx_fec_ethernet_on, (rtems_irq_disable) m8xx_fec_ethernet_off, (rtems_irq_is_enabled)m8xx_fec_ethernet_isOn};static voidm860_fec_initialize_hardware (struct m860_enet_struct *sc){ int i; unsigned char *hwaddr; rtems_status_code status; rtems_isr_entry old_handler; /* * Issue reset to FEC */ m8xx.fec.ecntrl=0x1; /* * Put ethernet transciever in reset */ m8xx.pgcra |= 0x80; /* * Configure I/O ports */ m8xx.pdpar = 0x1fff; m8xx.pddir = 0x1c58; /* * Take ethernet transciever out of reset */ m8xx.pgcra &= ~0x80; /* * Set SIU interrupt level to LVL2 * */ m8xx.fec.ivec = ((((unsigned) BSP_FAST_ETHERNET_CTRL)/2) << 29); /* * Set the TX and RX fifo sizes. For now, we'll split it evenly */ /* If you uncomment these, the FEC will not work right. m8xx.fec.r_fstart = ((m8xx.fec.r_bound & 0x3ff) >> 2) & 0x3ff; m8xx.fec.x_fstart = 0; */ /* * Set our physical address */ hwaddr = sc->arpcom.ac_enaddr; m8xx.fec.addr_low = (hwaddr[0] << 24) | (hwaddr[1] << 16) | (hwaddr[2] << 8) | (hwaddr[3] << 0); m8xx.fec.addr_high = (hwaddr[4] << 24) | (hwaddr[5] << 16); /* * Clear the hash table */ m8xx.fec.hash_table_high = 0; m8xx.fec.hash_table_low = 0; /* * Set up receive buffer size */ m8xx.fec.r_buf_size = 0x5f0; /* set to 1520 */ /* * 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 = m8xx_bd_allocate(sc->rxBdCount); sc->txBdBase = m8xx_bd_allocate(sc->txBdCount); m8xx.fec.r_des_start = (int)sc->rxBdBase; m8xx.fec.x_des_start = (int)sc->txBdBase; /* * Set up Receive Control Register: * Not promiscuous mode * MII mode * Half duplex * No loopback */ m8xx.fec.r_cntrl = 0x00000006; /* * Set up Transmit Control Register: * Half duplex * No heartbeat */ m8xx.fec.x_cntrl = 0x00000000; /* * Set up DMA function code: * Big-endian * DMA functino code = 0 */ m8xx.fec.fun_code = 0x78000000; /* * Initialize SDMA configuration register * SDMA ignores FRZ * FEC not aggressive * FEC arbitration ID = 0 => U-bus arbitration = 6 * RISC arbitration ID = 1 => U-bus arbitration = 5 */ m8xx.sdcr = 1; /* * Set MII speed to 2.5 MHz for 25 Mhz system clock */ m8xx.fec.mii_speed = 0x0a; m8xx.fec.mii_data = 0x58021000; /* * 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))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -