diff options
Diffstat (limited to 'bsps/arm/csb336/net/network.c')
-rw-r--r-- | bsps/arm/csb336/net/network.c | 708 |
1 files changed, 0 insertions, 708 deletions
diff --git a/bsps/arm/csb336/net/network.c b/bsps/arm/csb336/net/network.c deleted file mode 100644 index ddc671a4cd..0000000000 --- a/bsps/arm/csb336/net/network.c +++ /dev/null @@ -1,708 +0,0 @@ -/* - * MC9323MXL Ethernet driver - * - * Copyright (c) 2004 by Cogent Computer Systems - * Written by Jay Monkman <jtm@lopingdog.com> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include <machine/rtems-bsd-kernel-space.h> - -#include <rtems.h> -#include <rtems/rtems_bsdnet.h> -#include <mc9328mxl.h> -#include "lan91c11x.h" - -#include <stdio.h> -#include <string.h> - -#include <errno.h> -#include <rtems/error.h> -#include <rtems/bspIo.h> -#include <assert.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> - -/* RTEMS event used by interrupt handler to start receive daemon. */ -#define START_RECEIVE_EVENT RTEMS_EVENT_1 - -/* RTEMS event used to start transmit daemon. */ -#define START_TRANSMIT_EVENT RTEMS_EVENT_2 - -static void enet_isr(void *); -static void enet_isr_on(void); - -typedef struct { - unsigned long rx_packets; /* total packets received */ - unsigned long tx_packets; /* total packets transmitted */ - unsigned long rx_bytes; /* total bytes received */ - unsigned long tx_bytes; /* total bytes transmitted */ - unsigned long interrupts; /* total number of interrupts */ - unsigned long rx_interrupts; /* total number of rx interrupts */ - unsigned long tx_interrupts; /* total number of tx interrupts */ - unsigned long txerr_interrupts; /* total number of tx error interrupts */ - -} eth_stats_t; - -/* - * Hardware-specific storage - */ -typedef struct -{ - /* - * Connection to networking code - * This entry *must* be the first in the sonic_softc structure. - */ - struct arpcom arpcom; - - int accept_bcast; - - /* Tasks waiting for interrupts */ - rtems_id rx_task; - rtems_id tx_task; - - eth_stats_t stats; - -} mc9328mxl_enet_softc_t; - -static mc9328mxl_enet_softc_t softc; - - -/* function prototypes */ -int rtems_mc9328mxl_enet_attach(struct rtems_bsdnet_ifconfig *config, - void *chip); -void mc9328mxl_enet_init(void *arg); -void mc9328mxl_enet_init_hw(mc9328mxl_enet_softc_t *sc); -void mc9328mxl_enet_start(struct ifnet *ifp); -void mc9328mxl_enet_stop (mc9328mxl_enet_softc_t *sc); -void mc9328mxl_enet_tx_task (void *arg); -void mc9328mxl_enet_sendpacket (struct ifnet *ifp, struct mbuf *m); -void mc9328mxl_enet_rx_task(void *arg); -void mc9328mxl_enet_stats(mc9328mxl_enet_softc_t *sc); -static int mc9328mxl_enet_ioctl(struct ifnet *ifp, - ioctl_command_t command, caddr_t data); - - -int rtems_mc9328mxl_enet_attach ( - struct rtems_bsdnet_ifconfig *config, - void *chip /* only one ethernet, so no chip number */ - ) -{ - struct ifnet *ifp; - int mtu; - int unitnumber; - char *unitname; - int tmp; - - /* - * Parse driver name - */ - unitnumber = rtems_bsdnet_parse_driver_name(config, &unitname); - if (unitnumber < 0) { - return 0; - } - - /* - * Is driver free? - */ - if (unitnumber != 0) { - printf ("Bad MC9328MXL unit number.\n"); - return 0; - } - - ifp = &softc.arpcom.ac_if; - if (ifp->if_softc != NULL) { - printf ("Driver already in use.\n"); - return 0; - } - - /* zero out the control structure */ - memset( &softc, 0, sizeof(softc) ); - - - /* set the MAC address */ - tmp = lan91c11x_read_reg(LAN91C11X_IA0); - softc.arpcom.ac_enaddr[0] = tmp & 0xff; - softc.arpcom.ac_enaddr[1] = (tmp >> 8) & 0xff; - - tmp = lan91c11x_read_reg(LAN91C11X_IA2); - softc.arpcom.ac_enaddr[2] = tmp & 0xff; - softc.arpcom.ac_enaddr[3] = (tmp >> 8) & 0xff; - - tmp = lan91c11x_read_reg(LAN91C11X_IA4); - softc.arpcom.ac_enaddr[4] = tmp & 0xff; - softc.arpcom.ac_enaddr[5] = (tmp >> 8) & 0xff; - - if (config->mtu) { - mtu = config->mtu; - } else { - mtu = ETHERMTU; - } - - softc.accept_bcast = !config->ignore_broadcast; - - /* - * Set up network interface values - */ - ifp->if_softc = &softc; - ifp->if_unit = unitnumber; - ifp->if_name = unitname; - ifp->if_mtu = mtu; - ifp->if_init = mc9328mxl_enet_init; - ifp->if_ioctl = mc9328mxl_enet_ioctl; - ifp->if_start = mc9328mxl_enet_start; - ifp->if_output = ether_output; - ifp->if_flags = IFF_BROADCAST; - if (ifp->if_snd.ifq_maxlen == 0) { - ifp->if_snd.ifq_maxlen = ifqmaxlen; - } - - /* Attach the interface */ - if_attach (ifp); - ether_ifattach (ifp); - return 1; -} - -void mc9328mxl_enet_init(void *arg) -{ - mc9328mxl_enet_softc_t *sc = arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - - /* - *This is for stuff that only gets done once (mc9328mxl_enet_init() - * gets called multiple times - */ - if (sc->tx_task == 0) - { - /* Set up ENET hardware */ - mc9328mxl_enet_init_hw(sc); - - /* Start driver tasks */ - sc->rx_task = rtems_bsdnet_newproc("ENrx", - 4096, - mc9328mxl_enet_rx_task, - sc); - sc->tx_task = rtems_bsdnet_newproc("ENtx", - 4096, - mc9328mxl_enet_tx_task, - sc); - } /* if tx_task */ - - - /* Configure for promiscuous if needed */ - if (ifp->if_flags & IFF_PROMISC) { - lan91c11x_write_reg(LAN91C11X_RCR, - (lan91c11x_read_reg(LAN91C11X_RCR) | - LAN91C11X_RCR_PRMS)); - } - - - /* - * Tell the world that we're running. - */ - ifp->if_flags |= IFF_RUNNING; - - /* Enable TX/RX */ - lan91c11x_write_reg(LAN91C11X_TCR, - (lan91c11x_read_reg(LAN91C11X_TCR) | - LAN91C11X_TCR_TXENA)); - - lan91c11x_write_reg(LAN91C11X_RCR, - (lan91c11x_read_reg(LAN91C11X_RCR) | - LAN91C11X_RCR_RXEN)); - - -} /* mc9328mxl_enet_init() */ - -void mc9328mxl_enet_init_hw(mc9328mxl_enet_softc_t *sc) -{ - uint16_t stat; - uint16_t my = 0; - rtems_status_code status = RTEMS_SUCCESSFUL; - - lan91c11x_write_reg(LAN91C11X_RCR, LAN91C11X_RCR_RST); - lan91c11x_write_reg(LAN91C11X_RCR, 0); - rtems_task_wake_after(1); - - /* Reset the PHY */ - lan91c11x_write_phy_reg(PHY_CTRL, PHY_CTRL_RST); - while(lan91c11x_read_phy_reg(PHY_CTRL) & PHY_CTRL_RST) { - rtems_task_wake_after(1); - } - - - stat = lan91c11x_read_phy_reg(PHY_STAT); - - if(stat & PHY_STAT_CAPT4) { - my |= PHY_ADV_T4; - } -/* 100Mbs doesn't work, so we won't advertise it */ - - if(stat & PHY_STAT_CAPTXF) { - my |= PHY_ADV_TXFDX; - } - if(stat & PHY_STAT_CAPTXH) { - my |= PHY_ADV_TXHDX; - } - - if(stat & PHY_STAT_CAPTF) { - my |= PHY_ADV_10FDX; - } - - if(stat & PHY_STAT_CAPTH) { - my |= PHY_ADV_10HDX; - } - - my |= PHY_ADV_CSMA; - - lan91c11x_write_phy_reg(PHY_AD, my); - - - /* Enable Autonegotiation */ -#if 0 - lan91c11x_write_phy_reg(PHY_CTRL, - (PHY_CTRL_ANEGEN | PHY_CTRL_ANEGRST)); -#endif - - /* Enable full duplex, let MAC take care - * of padding and CRC. - */ - lan91c11x_write_reg(LAN91C11X_TCR, - (LAN91C11X_TCR_PADEN | - LAN91C11X_TCR_SWFDUP)); - - /* Disable promisc, don'tstrip CRC */ - lan91c11x_write_reg(LAN91C11X_RCR, 0); - - /* Enable auto-negotiation, LEDA is link, LEDB is traffic */ - lan91c11x_write_reg(LAN91C11X_RPCR, - (LAN91C11X_RPCR_ANEG | - LAN91C11X_RPCR_LS2B)); - - /* Don't add wait states, enable PHY power */ - lan91c11x_write_reg(LAN91C11X_CONFIG, - (LAN91C11X_CONFIG_NOWAIT | - LAN91C11X_CONFIG_PWR)); - - /* Disable error interrupts, enable auto release */ - lan91c11x_write_reg(LAN91C11X_CTRL, LAN91C11X_CTRL_AUTO); - - /* Reset MMU */ - lan91c11x_write_reg(LAN91C11X_MMUCMD, - LAN91C11X_MMUCMD_RESETMMU ); - - - rtems_task_wake_after(100); - /* Enable Autonegotiation */ - lan91c11x_write_phy_reg(PHY_CTRL, 0x3000); - rtems_task_wake_after(100); - - /* Enable Interrupts for RX */ - lan91c11x_write_reg(LAN91C11X_INT, LAN91C11X_INT_RXMASK); - - /* Enable interrupts on GPIO Port A3 */ - /* Make pin 3 an input */ - MC9328MXL_GPIOA_DDIR &= ~bit(3); - - /* Use GPIO function for pin 3 */ - MC9328MXL_GPIOA_GIUS |= bit(3); - - /* Set for active high, level triggered interupt */ - MC9328MXL_GPIOA_ICR1 = ((MC9328MXL_GPIOA_ICR1 & ~(3 << 6)) | - (2 << 6)); - - /* Enable GPIO port A3 interrupt */ - MC9328MXL_GPIOA_IMR |= bit(3); - - /* Install the interrupt handler */ - status = rtems_interrupt_handler_install( - BSP_INT_GPIO_PORTA, - "Network", - RTEMS_INTERRUPT_UNIQUE, - enet_isr, - (void *)BSP_INT_GPIO_PORTA - ); - assert(status == RTEMS_SUCCESSFUL); - enet_isr_on(); - -} /* mc9328mxl_enet_init_hw() */ - -void mc9328mxl_enet_start(struct ifnet *ifp) -{ - mc9328mxl_enet_softc_t *sc = ifp->if_softc; - - rtems_bsdnet_event_send(sc->tx_task, START_TRANSMIT_EVENT); - ifp->if_flags |= IFF_OACTIVE; -} - -void mc9328mxl_enet_stop (mc9328mxl_enet_softc_t *sc) -{ - struct ifnet *ifp = &sc->arpcom.ac_if; - - ifp->if_flags &= ~IFF_RUNNING; - - - /* Stop the transmitter and receiver. */ - lan91c11x_write_reg(LAN91C11X_TCR, - (lan91c11x_read_reg(LAN91C11X_TCR) & - ~LAN91C11X_TCR_TXENA)); - - lan91c11x_write_reg(LAN91C11X_RCR, - (lan91c11x_read_reg(LAN91C11X_RCR) & - ~LAN91C11X_RCR_RXEN)); - -} - -/* - * Driver transmit daemon - */ -void mc9328mxl_enet_tx_task(void *arg) -{ - mc9328mxl_enet_softc_t *sc = (mc9328mxl_enet_softc_t *)arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - struct mbuf *m; - rtems_event_set events; - - for (;;) - { - 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; - } - mc9328mxl_enet_sendpacket (ifp, m); - softc.stats.tx_packets++; - - } - ifp->if_flags &= ~IFF_OACTIVE; - } -} - -/* Send packet */ -void mc9328mxl_enet_sendpacket (struct ifnet *ifp, struct mbuf *m) -{ - struct mbuf *l = NULL; - int size = 0; - int tmp; - int i; - int start; - uint16_t d; - - /* How big is the packet ? */ - l = m; - do { - size += l->m_len; - l = l->m_next; - } while (l != NULL); - - /* Allocate a TX buffer */ - lan91c11x_write_reg(LAN91C11X_MMUCMD, - (LAN91C11X_MMUCMD_ALLOCTX | - (size >> 8))); - - /* Wait for the allocation */ - while ((lan91c11x_read_reg(LAN91C11X_INT) & LAN91C11X_INT_ALLOC) == 0) { - continue; - } - - tmp = lan91c11x_read_reg(LAN91C11X_PNR); - lan91c11x_write_reg(LAN91C11X_PNR, ((tmp >> 8) & 0xff)); - - /* Set the data pointer for auto increment */ - lan91c11x_write_reg(LAN91C11X_PTR, LAN91C11X_PTR_AUTOINC); - - /* A delay is needed between pointer and data access ?!? */ - for (i = 0; i < 10; i++) { - continue; - } - - /* Write status word */ - lan91c11x_write_reg(LAN91C11X_DATA, 0); - - /* Write byte count */ - if (size & 1) { - size++; - } - lan91c11x_write_reg(LAN91C11X_DATA, size + 6); - - lan91c11x_lock(); - - /* Copy the mbuf */ - l = m; - start = 0; - d = 0; - while (l != NULL) - { - uint8_t *data; - - data = mtod(l, uint8_t *); - - for (i = start; i < l->m_len; i++) { - if ((i & 1) == 0) { - d = data[i] << 8; - } else { - d = d | data[i]; - lan91c11x_write_reg_fast(LAN91C11X_DATA, htons(d)); - } - } - - /* If everything is 2 byte aligned, i will be even */ - start = (i & 1); - - l = l->m_next; - } - - /* write control byte */ - if (i & 1) { - lan91c11x_write_reg_fast(LAN91C11X_DATA, - htons(LAN91C11X_PKT_CTRL_ODD | d)); - } else { - lan91c11x_write_reg_fast(LAN91C11X_DATA, 0); - } - - lan91c11x_unlock(); - - /* Enable TX interrupts */ - lan91c11x_write_reg(LAN91C11X_INT, - (lan91c11x_read_reg(LAN91C11X_INT) | - LAN91C11X_INT_TXMASK | - LAN91C11X_INT_TXEMASK)); - - /* Enqueue it */ - lan91c11x_write_reg(LAN91C11X_MMUCMD, - LAN91C11X_MMUCMD_ENQUEUE); - - /* free the mbuf chain we just copied */ - m_freem(m); - -} /* mc9328mxl_enet_sendpacket () */ - - -/* reader task */ -void mc9328mxl_enet_rx_task(void *arg) -{ - mc9328mxl_enet_softc_t *sc = (mc9328mxl_enet_softc_t *)arg; - struct ifnet *ifp = &sc->arpcom.ac_if; - struct mbuf *m; - struct ether_header *eh; - rtems_event_set events; - int pktlen; - uint16_t rsw; - uint16_t bc; - uint16_t cbyte; - int i; - uint16_t int_reg; - - /* Input packet handling loop */ - while (1) { - rtems_bsdnet_event_receive( - START_RECEIVE_EVENT, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &events); - - /* Configure for reads from RX data area */ - lan91c11x_write_reg(LAN91C11X_PTR, - (LAN91C11X_PTR_AUTOINC | - LAN91C11X_PTR_RCV | - LAN91C11X_PTR_READ)); - - /* read the receive status word */ - rsw = lan91c11x_read_reg(LAN91C11X_DATA); - /* TBD: Need to check rsw here */ - - /* read the byte count */ - bc = lan91c11x_read_reg(LAN91C11X_DATA); - pktlen = (bc & 0x7ff) - 6; - - /* get an mbuf for this packet */ - MGETHDR(m, M_WAIT, MT_DATA); - - /* now get a cluster pointed to by the mbuf */ - /* since an mbuf by itself is too small */ - MCLGET(m, M_WAIT); - - lan91c11x_lock(); - - /* Copy the received packet into an mbuf */ - for (i = 0; i < (pktlen / 2); i++) { - ((uint16_t*)m->m_ext.ext_buf)[i] = - lan91c11x_read_reg_fast(LAN91C11X_DATA); - } - - cbyte = lan91c11x_read_reg_fast(LAN91C11X_DATA); - if (cbyte & LAN91C11X_PKT_CTRL_ODD) { - ((uint16_t*)m->m_ext.ext_buf)[i] = cbyte; - pktlen++; - } - lan91c11x_unlock(); - - /* Release the packets memory */ - lan91c11x_write_reg(LAN91C11X_MMUCMD, - LAN91C11X_MMUCMD_REMTOP); - - /* set the receiving interface */ - m->m_pkthdr.rcvif = ifp; - m->m_nextpkt = 0; - - /* set the length of the mbuf */ - m->m_len = pktlen - (sizeof(struct ether_header)); - m->m_pkthdr.len = m->m_len; - - /* strip off the ethernet header from the mbuf */ - /* but save the pointer to it */ - eh = mtod (m, struct ether_header *); - m->m_data += sizeof(struct ether_header); - - - softc.stats.rx_packets++; - - /* give all this stuff to the stack */ - ether_input(ifp, eh, m); - - /* renable RX interrupts */ - int_reg = lan91c11x_read_reg(LAN91C11X_INT); - int_reg |= LAN91C11X_INT_RXMASK; - lan91c11x_write_reg(LAN91C11X_INT, int_reg); - - } -} /* mc9328mxl_enet_rx_task */ - - -/* Show interface statistics */ -void mc9328mxl_enet_stats (mc9328mxl_enet_softc_t *sc) -{ - printf (" Total Interrupts:%-8lu", sc->stats.interrupts); - printf (" Rx Interrupts:%-8lu", sc->stats.rx_interrupts); - printf (" Tx Interrupts:%-8lu\n", sc->stats.tx_interrupts); - printf (" Tx Error Interrupts:%-8lu\n", sc->stats.txerr_interrupts); - printf (" Rx Packets:%-8lu", sc->stats.rx_packets); - printf (" Tx Packets:%-8lu\n", sc->stats.tx_packets); -} - - -/* Enables mc9328mxl_enet interrupts. */ -static void enet_isr_on(void) -{ - /* Enable interrupts */ - MC9328MXL_AITC_INTENNUM = MC9328MXL_INT_GPIO_PORTA; - - return; -} - -/* Driver ioctl handler */ -static int -mc9328mxl_enet_ioctl (struct ifnet *ifp, ioctl_command_t command, caddr_t data) -{ - mc9328mxl_enet_softc_t *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: - mc9328mxl_enet_stop (sc); - break; - - case IFF_UP: - mc9328mxl_enet_init (sc); - break; - - case IFF_UP | IFF_RUNNING: - mc9328mxl_enet_stop (sc); - mc9328mxl_enet_init (sc); - break; - - default: - break; - } /* switch (if_flags) */ - break; - - case SIO_RTEMS_SHOW_STATS: - mc9328mxl_enet_stats (sc); - break; - - /* - * FIXME: All sorts of multicast commands need to be added here! - */ - default: - error = EINVAL; - break; - } /* switch (command) */ - return error; -} - -/* interrupt handler */ -static void enet_isr(void * unused) -{ - uint16_t int_reg; - - softc.stats.interrupts++; - /* get the ISR status and determine RX or TX */ - int_reg = lan91c11x_read_reg(LAN91C11X_INT); - - /* Handle RX interrupts */ - if ((int_reg & LAN91C11X_INT_RX) && (int_reg & LAN91C11X_INT_RXMASK)) { - softc.stats.rx_interrupts++; - - /* Disable the interrupt */ - int_reg &= ~LAN91C11X_INT_RXMASK; - - rtems_bsdnet_event_send (softc.rx_task, START_RECEIVE_EVENT); - } - - /* Handle TX Empty interrupts */ - if ((int_reg & LAN91C11X_INT_TXE) && (int_reg & LAN91C11X_INT_TXEMASK)) { - softc.stats.tx_interrupts++; - - /* Disable the interrupt */ - int_reg &= ~LAN91C11X_INT_TXEMASK; - - /* Acknowledge the interrupt */ - int_reg |= LAN91C11X_INT_TXE; - - rtems_bsdnet_event_send(softc.tx_task, START_TRANSMIT_EVENT); - - } - - /* Handle interrupts for transmit errors */ - if ((int_reg & LAN91C11X_INT_TX) && (int_reg & LAN91C11X_INT_TXMASK)) { - softc.stats.txerr_interrupts++; - printk("Caught TX interrupt - error on transmission\n"); - } - - /* Update the interrupt register on the 91c11x */ - lan91c11x_write_reg(LAN91C11X_INT, int_reg); - - /* clear GPIO Int. status */ - MC9328MXL_GPIOA_ISR |= bit(3); -} - |