diff options
Diffstat (limited to 'bsps/lm32/shared/net/tsmac.c')
-rw-r--r-- | bsps/lm32/shared/net/tsmac.c | 822 |
1 files changed, 822 insertions, 0 deletions
diff --git a/bsps/lm32/shared/net/tsmac.c b/bsps/lm32/shared/net/tsmac.c new file mode 100644 index 0000000000..6779f336d4 --- /dev/null +++ b/bsps/lm32/shared/net/tsmac.c @@ -0,0 +1,822 @@ +/* + * This file contains definitions for LatticeMico32 TSMAC (Tri-Speed MAC) + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * 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. + * + * Jukka Pietarinen <jukka.pietarinen@mrf.fi>, 2008, + * Micro-Research Finland Oy + */ + +#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ +#define _KERNEL + +#include <rtems.h> +#include <bsp.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <rtems/error.h> +#include <rtems/bspIo.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 "../include/system_conf.h" +#include "tsmac.h" +#include "dp83848phy.h" + +struct tsmac_softc { + struct arpcom arpcom; + void *ioaddr; + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + /* + * Statistics + */ + int rxInterrupts; + int rxPktIgnore; + int rxLenCheckError; + int rxLongFrame; + int rxShortFrame; + int rxIPGViolation; + int rxCRCError; + int rxOKPackets; + int rxControlFrame; + int rxPauseFrame; + int rxMulticast; + int rxBroadcast; + int rxVLANTag; + int rxPreShrink; + int rxDribNib; + int rxUnsupOPCD; + int rxByteCnt; + int rxFifoFull; + + int txInterrupts; + int txUnicast; + int txPauseFrame; + int txMulticast; + int txBroadcast; + int txVLANTag; + int txBadFCS; + int txJumboCnt; + int txByteCnt; + int txLostCarrier; + int txFifoFull; +}; + +/* + * Macros to access tsmac wrapper registers. + */ + +static inline uint32_t tsmacread(unsigned int reg) +{ + return *((uint32_t *)(TS_MAC_CORE_BASE_ADDRESS + reg)); +} + +static inline void tsmacwrite(unsigned int reg, uint32_t value) +{ + *((uint32_t *)(TS_MAC_CORE_BASE_ADDRESS + reg)) = value; +} + +/* + * tsmac is a wishbone to MAC wrapper. + * The macros below access to MAC registers. + */ + +static inline uint16_t tsmacregread(unsigned int reg) +{ + tsmacwrite(LM32_TSMAC_MAC_REGS_ADDR_RW, reg); + return *((uint16_t *)(TS_MAC_CORE_BASE_ADDRESS + LM32_TSMAC_MAC_REGS_DATA + 2)); +} + +static inline void tsmacregwrite(unsigned int reg, uint16_t value) +{ + *((uint16_t *)(TS_MAC_CORE_BASE_ADDRESS + LM32_TSMAC_MAC_REGS_DATA + 2)) = value; + tsmacwrite(LM32_TSMAC_MAC_REGS_ADDR_RW, REGS_ADDR_WRITE | reg); +} + +/* +#define DEBUG 1 +*/ + +/* We support one interface */ + +#define TSMAC_NUM 1 +#define TSMAC_NAME "TSMAC" +#define TSMAC_MAC0 0x00 +#define TSMAC_MAC1 0x0E +#define TSMAC_MAC2 0xB2 +#define TSMAC_MAC3 0x00 +#define TSMAC_MAC4 0x00 +#define TSMAC_MAC5 0x01 + +/* + * The interrupt vector number associated with the tsmac device + * driver. + */ + +#define TSMAC_VECTOR ( TS_MAC_CORE_IRQ ) +#define TSMAC_IRQMASK ( 1 << TSMAC_VECTOR ) + +rtems_isr tsmac_interrupt_handler(rtems_vector_number vector); + +extern rtems_isr_entry set_vector(rtems_isr_entry handler, + rtems_vector_number vector, int type); + +/* + * Macros to access PHY registers through the (G)MII + */ + +uint16_t tsmacphyread(unsigned int reg) +{ + tsmacregwrite(LM32_TSMAC_GMII_MNG_CTL_BYTE0, + ((DEFAULT_PHY_ADDRESS & GMII_MNG_CTL_PHY_ADD_MASK) << + GMII_MNG_CTL_PHY_ADD_SHIFT) | + ((reg & GMII_MNG_CTL_REG_ADD_MASK) << + GMII_MNG_CTL_REG_ADD_SHIFT) | + GMII_MNG_CTL_READ_PHYREG); + + /* Wait for management interface to be ready */ + while(!(tsmacregread(LM32_TSMAC_GMII_MNG_CTL_BYTE0) & GMII_MNG_CTL_CMD_FIN)); + + return tsmacregread(LM32_TSMAC_GMII_MNG_DAT_BYTE0); +} + +void tsmacphywrite(unsigned int reg, uint16_t value) +{ + tsmacregwrite(LM32_TSMAC_GMII_MNG_DAT_BYTE0, value); + tsmacregwrite(LM32_TSMAC_GMII_MNG_CTL_BYTE0, + ((DEFAULT_PHY_ADDRESS & GMII_MNG_CTL_PHY_ADD_MASK) << + GMII_MNG_CTL_PHY_ADD_SHIFT) | + ((reg & GMII_MNG_CTL_REG_ADD_MASK) << + GMII_MNG_CTL_REG_ADD_SHIFT) | + GMII_MNG_CTL_WRITE_PHYREG); + + /* Wait for management interface to be ready */ + while(!(tsmacregread(LM32_TSMAC_GMII_MNG_CTL_BYTE0) & GMII_MNG_CTL_CMD_FIN)); +} + +/* + * Event definitions + */ +#define INTERRUPT_EVENT RTEMS_EVENT_1 +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +static struct tsmac_softc tsmac_softc[TSMAC_NUM]; + +#ifdef CPU_U32_FIX + +/* + * Routine to align the received packet so that the ip header + * is on a 32-bit boundary. Necessary for cpu's that do not + * allow unaligned loads and stores and when the 32-bit DMA + * mode is used. + * + * Transfers are done on word basis to avoid possibly slow byte + * and half-word writes. + * + * Copied over from sonic.c driver + */ + +void ipalign(struct mbuf *m) +{ + unsigned int *first, *last, data; + unsigned int tmp = 0; + + if ((((int) m->m_data) & 2) && (m->m_len)) { + last = (unsigned int *) ((((int) m->m_data) + m->m_len + 8) & ~3); + first = (unsigned int *) (((int) m->m_data) & ~3); + tmp = *first << 16; + first++; + do { + data = *first; + *first = tmp | (data >> 16); + tmp = data << 16; + first++; + } while (first <= last); + + m->m_data = (caddr_t)(((int) m->m_data) + 2); + } +} +#endif + +/* + * Receive task + */ +static void tsmac_rxDaemon(void *arg) +{ + struct tsmac_softc *tsmac = (struct tsmac_softc *) arg; + struct ifnet *ifp = &tsmac->arpcom.ac_if; + rtems_event_set events; + int rxq, count, len, data; + +#ifdef DEBUG + printk(TSMAC_NAME ": tsmac_rxDaemon\n"); +#endif + + for(;;) + { + rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, + RTEMS_WAIT | RTEMS_EVENT_ANY, + RTEMS_NO_TIMEOUT, + &events); + +#ifdef DEBUG + printk(TSMAC_NAME ": tsmac_rxDaemon wakeup\n"); +#endif + + for (;;) + { + struct mbuf* m; + struct ether_header* eh; + uint32_t *buf; + + /* Get number of RX frames in RX FIFO */ + rxq = tsmacread(LM32_TSMAC_RX_FRAMES_CNT); + + if (rxq == 0) + break; + + /* Get length of frame */ + len = tsmacread(LM32_TSMAC_RX_LEN_FIFO); +#ifdef DEBUG + printk(TSMAC_NAME ": Frames %d, len 0x%04x (%d)\n", + rxq, len, len); +#endif + + /* + * Get memory for packet + */ + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + + m->m_pkthdr.rcvif = ifp; + + buf = (uint32_t *) mtod(m, uint32_t*); + for (count = 0; count < len; count += 4) + { + data = tsmacread(LM32_TSMAC_RX_DATA_FIFO); + *buf++ = data; +#ifdef DEBUG + printk("%08x ", data); +#endif + } +#ifdef DEBUG + printk("\n"); +#endif + + m->m_len = m->m_pkthdr.len = + len - sizeof(uint32_t) - sizeof(struct ether_header); + eh = mtod(m, struct ether_header*); + m->m_data += sizeof(struct ether_header); + +#ifdef CPU_U32_FIX + ipalign(m); /* Align packet on 32-bit boundary */ +#endif + + /* Notify the ip stack that there is a new packet */ + ether_input(ifp, eh, m); + + /* + * Release RX frame + */ + } + } +} + +static unsigned char tsmac_txbuf[2048]; + +static void tsmac_sendpacket(struct ifnet *ifp, struct mbuf *m) +{ + struct mbuf *nm = m; + int len = 0, i; + uint32_t *buf; + +#ifdef DEBUG + printk(TSMAC_NAME ": tsmac_sendpacket\n"); +#endif + + do + { +#ifdef DEBUG + printk("mbuf: 0x%08x len %03x: ", nm->m_data, nm->m_len); + for (i = 0; i < nm->m_len; i++) + { + printk("%02x", mtod(nm, unsigned char*)[i]); + if (i & 1) + printk(" "); + } + printk("\n"); +#endif + + if (nm->m_len > 0) + { + memcpy(&tsmac_txbuf[len], (char *)nm->m_data, nm->m_len); + len += nm->m_len; + } + } + while ((nm = nm->m_next) != 0); + + buf = (uint32_t *) tsmac_txbuf; + for (i = 0; i < len; i += 4) + { +#ifdef DEBUG + printk("%08x", *buf); +#endif + tsmacwrite(LM32_TSMAC_TX_DATA_FIFO, *buf++); + } +#ifdef DEBUG + printk("\n"); +#endif + + /* + * Enqueue TX frame + */ + tsmacwrite(LM32_TSMAC_TX_LEN_FIFO, len); +} + +/* + * Transmit task + */ +static void tsmac_txDaemon(void *arg) +{ + struct tsmac_softc *tsmac = (struct tsmac_softc *) arg; + struct ifnet *ifp = &tsmac->arpcom.ac_if; + struct mbuf *m; + rtems_event_set events; + int txq; + +#ifdef DEBUG + printk(TSMAC_NAME ": tsmac_txDaemon\n"); +#endif + + for (;;) + { + /* + * Wait for packet + */ + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT | INTERRUPT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); +#ifdef DEBUG + printk(TSMAC_NAME ": tsmac_txDaemon event\n"); +#endif + for (;;) + { + /* + * Here we should read amount of transmit memory available + */ + + txq = 2048; + + if (txq < ifp->if_mtu) + { + /* + * Here we need to enable transmit done IRQ + */ +#ifdef DEBUG + printk(TSMAC_NAME ": TXMA %d < MTU + CW%d\n", txq, + ifp->if_mtu); +#endif + break; + } + + /* + * Get the next mbuf chain to transmit. + */ + IF_DEQUEUE(&ifp->if_snd, m); +#ifdef DEBUG + printk(TSMAC_NAME ": mbuf %08x\n", (int) m); +#endif + if (!m) + break; + tsmac_sendpacket(ifp, m); + + m_freem(m); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} + +/* + * Initialize TSMAC hardware + */ +void tsmac_init_hardware(struct tsmac_softc *tsmac) +{ + unsigned char *mac_addr; + int version_id, phyid, stat; + +#ifdef DEBUG + printk(TSMAC_NAME ": tsmac_init_hardware\n"); +#endif + + version_id = tsmacread(LM32_TSMAC_VERID); +#ifdef DEBUG + printk(TSMAC_NAME ": Version ID %08x\n", version_id); +#endif + +#ifdef DEBUG + printk(TSMAC_NAME ": MAC MODE %04x\n", tsmacregread(LM32_TSMAC_MODE_BYTE0)); + printk(TSMAC_NAME ": MAC TX_RX_CTL %04x\n", tsmacregread(LM32_TSMAC_TX_RX_CTL_BYTE0)); + printk(TSMAC_NAME ": MAC MAX_PKT_SIZE %04x\n", tsmacregread(LM32_TSMAC_MAX_PKT_SIZE_BYTE0)); + printk(TSMAC_NAME ": MAC IPG_VAL %04x\n", tsmacregread(LM32_TSMAC_IPG_VAL_BYTE0)); + printk(TSMAC_NAME ": MAC MAC_ADDR0 %04x\n", + tsmacregread(LM32_TSMAC_MAC_ADDR_0_BYTE0)); + printk(TSMAC_NAME ": MAC MAC_ADDR1 %04x\n", + tsmacregread(LM32_TSMAC_MAC_ADDR_1_BYTE0)); + printk(TSMAC_NAME ": MAC MAC_ADDR2 %04x\n", + tsmacregread(LM32_TSMAC_MAC_ADDR_2_BYTE0)); + printk(TSMAC_NAME ": MAC TX_RX_STS %04x\n", + tsmacregread(LM32_TSMAC_TX_RX_STS_BYTE0)); +#endif + + /* + * Set our physical address + */ + mac_addr = tsmac->arpcom.ac_enaddr; + tsmacregwrite(LM32_TSMAC_MAC_ADDR_0_BYTE0, (mac_addr[0] << 8) | mac_addr[1]); + tsmacregwrite(LM32_TSMAC_MAC_ADDR_1_BYTE0, (mac_addr[2] << 8) | mac_addr[3]); + tsmacregwrite(LM32_TSMAC_MAC_ADDR_2_BYTE0, (mac_addr[4] << 8) | mac_addr[5]); + +#ifdef DEBUG + printk(TSMAC_NAME ": After setting MAC address.\n"); + printk(TSMAC_NAME ": MAC MAC_ADDR0 %04x\n", + tsmacregread(LM32_TSMAC_MAC_ADDR_0_BYTE0)); + printk(TSMAC_NAME ": MAC MAC_ADDR1 %04x\n", + tsmacregread(LM32_TSMAC_MAC_ADDR_1_BYTE0)); + printk(TSMAC_NAME ": MAC MAC_ADDR2 %04x\n", + tsmacregread(LM32_TSMAC_MAC_ADDR_2_BYTE0)); +#endif + + /* + * Configure PHY + */ + + phyid = tsmacphyread(PHY_PHYIDR1); +#ifdef DEBUG + printk(TSMAC_NAME ": PHYIDR1 %08x\n", phyid); +#endif + phyid = tsmacphyread(PHY_PHYIDR2); +#ifdef DEBUG + printk(TSMAC_NAME ": PHYIDR2 %08x\n", phyid); +#endif + +#ifdef TSMAC_FORCE_10BASET + /* Force 10baseT mode, no AN, full duplex */ + tsmacphywrite(PHY_BMCR, PHY_BMCR_DUPLEX_MODE); + stat = tsmacphyread(PHY_BMCR); +#ifdef DEBUG + printk(TSMAC_NAME ": PHY BMCR %04x, wrote %04x\n", stat, + PHY_BMCR_DUPLEX_MODE); +#endif + stat = tsmacphyread(PHY_BMSR); +#ifdef DEBUG + printk(TSMAC_NAME ": PHY BMSR %04x\n", stat); +#endif + /* Support for 10baseT modes only */ + tsmacphywrite(PHY_ANAR, PHY_ANAR_10_FD | PHY_ANAR_10 | PHY_ANAR_SEL_DEF); + stat = tsmacphyread(PHY_ANAR); +#ifdef DEBUG + printk(TSMAC_NAME ": PHY ANAR %04x, wrote %04x\n", stat, + PHY_ANAR_10_FD | PHY_ANAR_10 | PHY_ANAR_SEL_DEF); +#endif +#endif /* TSMAC_FORCE_10BASET */ + stat = tsmacphyread(PHY_PHYSTS); +#ifdef DEBUG + printk(TSMAC_NAME ": PHY PHYSTS %04x\n", stat); +#endif + + /* Enable receive and transmit interrupts */ + tsmacwrite(LM32_TSMAC_INTR_ENB, INTR_ENB | + INTR_RX_SMRY | INTR_TX_SMRY | + INTR_RX_PKT_RDY | INTR_TX_PKT_SENT); +} + +/* + * Initialize and start the device + */ +void tsmac_init(void *arg) +{ + struct tsmac_softc *tsmac = &tsmac_softc[0]; + struct ifnet *ifp = &tsmac->arpcom.ac_if; + +#ifdef DEBUG + printk(TSMAC_NAME ": tsmac_init, tsmac->txDaemonTid = 0x%x\n", + tsmac->txDaemonTid); +#endif + + if (tsmac->txDaemonTid == 0) + { + /* + * Initialize hardware + */ + tsmac_init_hardware(tsmac); + + /* + * Start driver tasks + */ + tsmac->txDaemonTid = rtems_bsdnet_newproc ("TSMACtx", 4096, + tsmac_txDaemon, tsmac); + tsmac->rxDaemonTid = rtems_bsdnet_newproc ("TSMACrx", 4096, + tsmac_rxDaemon, tsmac); + /* + * Setup interrupt handler + */ + set_vector( tsmac_interrupt_handler, TSMAC_VECTOR, 1 ); + + /* Interrupt line for TSMAC */ + lm32_interrupt_unmask(TSMAC_IRQMASK); + } + + ifp->if_flags |= IFF_RUNNING; + + /* + * Receive broadcast + */ + + tsmacregwrite(LM32_TSMAC_TX_RX_CTL_BYTE0, TX_RX_CTL_RECEIVE_BRDCST | + TX_RX_CTL_RECEIVE_PAUSE); + + /* + * Enable transmitter + * Flow control enable + * Enable receiver + */ + + tsmacregwrite(LM32_TSMAC_MODE_BYTE0, MODE_TX_EN | MODE_RX_EN | MODE_FC_EN); + + /* + * Wake up receive task to receive packets in queue + */ + rtems_bsdnet_event_send(tsmac->rxDaemonTid, INTERRUPT_EVENT); +} + +void tsmac_stop(struct ifnet *ifp) +{ + /* + * Mask tsmac interrupts + */ + lm32_interrupt_mask(TSMAC_IRQMASK); + + ifp->if_flags &= ~IFF_RUNNING; + + /* + * Disable transmitter and receiver + */ + tsmacregwrite(LM32_TSMAC_MODE_BYTE0, 0); +} + +/* + * Send packet + */ +void tsmac_start(struct ifnet *ifp) +{ + struct tsmac_softc *tsmac = ifp->if_softc; + + rtems_bsdnet_event_send (tsmac->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +void tsmac_stats(struct tsmac_softc *tsmac) +{ + /* + * Update counters from TSMAC MIB counters + */ + + tsmac->rxPktIgnore = tsmacread(LM32_TSMAC_RX_PKT_IGNR_CNT); + tsmac->rxLenCheckError = tsmacread(LM32_TSMAC_RX_LEN_CHK_ERR_CNT); + tsmac->rxLongFrame = tsmacread(LM32_TSMAC_RX_LNG_FRM_CNT); + tsmac->rxShortFrame = tsmacread(LM32_TSMAC_RX_SHRT_FRM_CNT); + tsmac->rxIPGViolation = tsmacread(LM32_TSMAC_RX_IPG_VIOL_CNT); + tsmac->rxCRCError = tsmacread(LM32_TSMAC_RX_CRC_ERR_CNT); + tsmac->rxOKPackets = tsmacread(LM32_TSMAC_RX_OK_PKT_CNT); + tsmac->rxControlFrame = tsmacread(LM32_TSMAC_RX_CTL_FRM_CNT); + tsmac->rxPauseFrame = tsmacread(LM32_TSMAC_RX_PAUSE_FRM_CNT); + tsmac->rxMulticast = tsmacread(LM32_TSMAC_RX_MULTICAST_CNT); + tsmac->rxBroadcast = tsmacread(LM32_TSMAC_RX_BRDCAST_CNT); + tsmac->rxVLANTag = tsmacread(LM32_TSMAC_RX_VLAN_TAG_CNT); + tsmac->rxPreShrink = tsmacread(LM32_TSMAC_RX_PRE_SHRINK_CNT); + tsmac->rxDribNib = tsmacread(LM32_TSMAC_RX_DRIB_NIB_CNT); + tsmac->rxUnsupOPCD = tsmacread(LM32_TSMAC_RX_UNSUP_OPCD_CNT); + tsmac->rxByteCnt = tsmacread(LM32_TSMAC_RX_BYTE_CNT); + + tsmac->txUnicast = tsmacread(LM32_TSMAC_TX_UNICAST_CNT); + tsmac->txPauseFrame = tsmacread(LM32_TSMAC_TX_PAUSE_FRM_CNT); + tsmac->txMulticast = tsmacread(LM32_TSMAC_TX_MULTICAST_CNT); + tsmac->txBroadcast = tsmacread(LM32_TSMAC_TX_BRDCAST_CNT); + tsmac->txVLANTag = tsmacread(LM32_TSMAC_TX_VLAN_TAG_CNT); + tsmac->txBadFCS = tsmacread(LM32_TSMAC_TX_BAD_FCS_CNT); + tsmac->txJumboCnt = tsmacread(LM32_TSMAC_TX_JUMBO_CNT); + tsmac->txByteCnt = tsmacread(LM32_TSMAC_TX_BYTE_CNT); + + printk("RX Interrupts: %8d", tsmac->rxInterrupts); + printk(" RX Len Chk Error: %8d", tsmac->rxLenCheckError); + printk(" RX Long Frame: %8d\n", tsmac->rxLongFrame); + printk("RX Short Frame: %8d", tsmac->rxShortFrame); + printk(" RX IPG Violation: %8d", tsmac->rxIPGViolation); + printk(" RX CRC Errors: %8d\n", tsmac->rxCRCError); + printk("RX OK Packets: %8d", tsmac->rxOKPackets); + printk(" RX Control Frame: %8d", tsmac->rxControlFrame); + printk(" RX Pause Frame: %8d\n", tsmac->rxPauseFrame); + printk("RX Multicast: %8d", tsmac->rxMulticast); + printk(" RX Broadcast: %8d", tsmac->rxBroadcast); + printk(" RX VLAN Tag: %8d\n", tsmac->rxVLANTag); + printk("RX Pre Shrink: %8d", tsmac->rxPreShrink); + printk(" RX Dribb. Nibble: %8d", tsmac->rxDribNib); + printk(" RX Unsupp. OPCD: %8d\n", tsmac->rxUnsupOPCD); + printk("RX Byte Count: %8d", tsmac->rxByteCnt); + printk(" RX FIFO Full: %8d\n", tsmac->rxFifoFull); + + printk("TX Interrupts: %8d", tsmac->txInterrupts); + printk(" TX Unicast: %8d", tsmac->txUnicast); + printk(" TX Pause Frame: %8d\n", tsmac->txPauseFrame); + printk("TX Multicast: %8d", tsmac->txMulticast); + printk(" TX Broadcast: %8d", tsmac->txBroadcast); + printk(" TX VLAN Tag: %8d\n", tsmac->txVLANTag); + printk("TX Bad FSC: %8d", tsmac->txBadFCS); + printk(" TX Jumbo Frame: %8d", tsmac->txJumboCnt); + printk(" TX Byte Count: %8d\n", tsmac->txByteCnt); + printk("TX FIFO Full: %8d\n", tsmac->txFifoFull); +} + +/* + * TSMAC ioctl handler + */ + +int tsmac_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data) +{ + struct tsmac_softc *tsmac = 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: + tsmac_stop ((struct ifnet *) tsmac); + break; + + case IFF_UP: + tsmac_init ((struct ifnet *) tsmac); + break; + + case IFF_UP | IFF_RUNNING: + tsmac_stop ((struct ifnet *) tsmac); + tsmac_init ((struct ifnet *) tsmac); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + tsmac_stats (tsmac); + break; + + default: + error = EINVAL; + break; + } + return error; +} + +/* + * Attach a TSMAC driver + */ +int rtems_tsmac_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching) +{ + struct tsmac_softc *tsmac; + struct ifnet *ifp; + int mtu, i; + int unit; + char *unitName; + + if ((unit = rtems_bsdnet_parse_driver_name(config, &unitName)) < 0) + { + printk(TSMAC_NAME ": Driver name parsing failed.\n"); + return 0; + } + + if ((unit < 0) || (unit >= TSMAC_NUM)) + { + printk(TSMAC_NAME ": Bad unit number %d.\n", unit); + return 0; + } + + tsmac = &tsmac_softc[unit]; + + ifp = &tsmac->arpcom.ac_if; + if (ifp->if_softc != NULL) + { + printk(TSMAC_NAME ": Driver already in use.\n"); + return 0; + } + + /* Base address for TSMAC */ + if (config->bpar == 0) + { + printk(TSMAC_NAME ": Using default base address 0x%08x.\n", TS_MAC_CORE_BASE_ADDRESS); + config->bpar = TS_MAC_CORE_BASE_ADDRESS; + } + tsmac->ioaddr = config->bpar; + + /* Hardware address for TSMAC */ + if (config->hardware_address == 0) + { + printk(TSMAC_NAME ": Using default hardware address.\n"); + tsmac->arpcom.ac_enaddr[0] = TSMAC_MAC0; + tsmac->arpcom.ac_enaddr[1] = TSMAC_MAC1; + tsmac->arpcom.ac_enaddr[2] = TSMAC_MAC2; + tsmac->arpcom.ac_enaddr[3] = TSMAC_MAC3; + tsmac->arpcom.ac_enaddr[4] = TSMAC_MAC4; + tsmac->arpcom.ac_enaddr[5] = TSMAC_MAC5; + } + else + memcpy(tsmac->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); + + printk(TSMAC_NAME ": MAC address "); + for (i = 0; i < ETHER_ADDR_LEN; i++) + { + printk("%02x", tsmac->arpcom.ac_enaddr[i]); + if (i != ETHER_ADDR_LEN-1) + printk(":"); + else + printk("\n"); + } + + if (config->mtu) + mtu = config->mtu; + else + mtu = ETHERMTU; + + /* + * Set up network interface values + */ + ifp->if_softc = tsmac; + ifp->if_unit = unit; + ifp->if_name = unitName; + ifp->if_mtu = mtu; + ifp->if_init = tsmac_init; + ifp->if_ioctl = tsmac_ioctl; + ifp->if_start = tsmac_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + + if (ifp->if_snd.ifq_maxlen == 0) + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + if_attach(ifp); + ether_ifattach(ifp); + + return 1; +} + +rtems_isr tsmac_interrupt_handler(rtems_vector_number vector) +{ + struct tsmac_softc *tsmac = &tsmac_softc[0]; + uint32_t irq_stat, rx_stat, tx_stat; + + irq_stat = tsmacread(LM32_TSMAC_INTR_SRC); + if (irq_stat & INTR_RX_PKT_RDY) + { + tsmac->rxInterrupts++; + rtems_bsdnet_event_send(tsmac->rxDaemonTid, INTERRUPT_EVENT); + } + + if (irq_stat & INTR_TX_PKT_SENT) + { + tsmac->txInterrupts++; + rtems_bsdnet_event_send(tsmac->txDaemonTid, INTERRUPT_EVENT); + } + + rx_stat = tsmacread(LM32_TSMAC_RX_STATUS); + if (rx_stat & STAT_RX_FIFO_FULL) + tsmac->rxFifoFull++; + + tx_stat = tsmacread(LM32_TSMAC_TX_STATUS); + if (tx_stat & STAT_TX_FIFO_FULL) + tsmac->txFifoFull++; + + lm32_interrupt_ack(TSMAC_IRQMASK); +} + |