diff options
Diffstat (limited to 'bsps/lm32/shared')
-rw-r--r-- | bsps/lm32/shared/net/dp83848phy.h | 186 | ||||
-rw-r--r-- | bsps/lm32/shared/net/network.c | 319 | ||||
-rw-r--r-- | bsps/lm32/shared/net/network.h | 31 | ||||
-rw-r--r-- | bsps/lm32/shared/net/tsmac.c | 822 | ||||
-rw-r--r-- | bsps/lm32/shared/net/tsmac.h | 172 |
5 files changed, 1530 insertions, 0 deletions
diff --git a/bsps/lm32/shared/net/dp83848phy.h b/bsps/lm32/shared/net/dp83848phy.h new file mode 100644 index 0000000000..edc40cbb11 --- /dev/null +++ b/bsps/lm32/shared/net/dp83848phy.h @@ -0,0 +1,186 @@ +/** + * @file + * @ingroup lm32_tsmac + * @brief LatticeMico32 TSMAC (Tri-Speed MAC) definitions + */ + +/* + * 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 + */ + +#ifndef _DP83848PHY_H +#define _DP83848PHY_H + +#define DEFAULT_PHY_ADDRESS (0x01) + +#define PHY_BMCR (0x00) +#define PHY_BMCR_RESET (1<<15) +#define PHY_BMCR_LOOPBACK (1<<14) +#define PHY_BMCR_SPEEDSEL (1<<13) +#define PHY_BMCR_AN_ENA (1<<12) +#define PHY_BMCR_PWRDWN (1<<11) +#define PHY_BMCR_ISOLATE (1<<10) +#define PHY_BMCR_RESTART_AN (1<<9) +#define PHY_BMCR_DUPLEX_MODE (1<<8) +#define PHY_BMCR_COLL_TEST (1<<7) +#define PHY_BMSR (0x01) +#define PHY_BMSR_100_T4 (1<<15) +#define PHY_BMSR_100_TX_FD (1<<14) +#define PHY_BMSR_100_TX_HD (1<<13) +#define PHY_BMSR_10_T_FD (1<<12) +#define PHY_BMSR_10_T_HD (1<<11) +#define PHY_BMSR_PRESUP (1<<6) +#define PHY_BMSR_AN_CMPL (1<<5) +#define PHY_BMSR_REM_FLT (1<<4) +#define PHY_BMSR_AN_AB (1<<3) +#define PHY_BMSR_LINK_STAT (1<<2) +#define PHY_BMSR_JABBDET (1<<1) +#define PHY_BMSR_EXT_CAP (1<<0) +#define PHY_PHYIDR1 (0x02) +#define DEFAULT_PHYIDR1 (0x2000) +#define PHY_PHYIDR2 (0x03) +#define DEFAULT_PHYIDR2 (0x5C90) +#define PHY_ANAR (0x04) +#define PHY_ANAR_NP (1<<15) +#define PHY_ANAR_RF (1<<13) +#define PHY_ANAR_ASM_DIR (1<<11) +#define PHY_ANAR_PAUSE (1<<10) +#define PHY_ANAR_T4 (1<<9) +#define PHY_ANAR_TX_FD (1<<8) +#define PHY_ANAR_TX (1<<7) +#define PHY_ANAR_10_FD (1<<6) +#define PHY_ANAR_10 (1<<5) +#define PHY_ANAR_SEL_MASK (0x0f) +#define PHY_ANAR_SEL_SHIFT (0) +#define PHY_ANAR_SEL_DEF (1) +#define PHY_ANLPAR (0x05) +#define PHY_ANLPAR_NP (1<<15) +#define PHY_ANLPAR_ACK (1<<14) +#define PHY_ANLPAR_RF (1<<13) +#define PHY_ANLPAR_ASM_DIR (1<<11) +#define PHY_ANLPAR_PAUSE (1<<10) +#define PHY_ANLPAR_T4 (1<<9) +#define PHY_ANLPAR_TX_FD (1<<8) +#define PHY_ANLPAR_TX (1<<7) +#define PHY_ANLPAR_10_FD (1<<6) +#define PHY_ANLPAR_10 (1<<5) +#define PHY_ANLPAR_SEL_MASK (0x0f) +#define PHY_ANLPAR_SEL_SHIFT (0) +#define PHY_ANLPARNP (0x05) +#define PHY_ANLPARNP_NP (1<<15) +#define PHY_ANLPARNP_ACK (1<<14) +#define PHY_ANLPARNP_MP (1<<13) +#define PHY_ANLPARNP_ACK2 (1<<12) +#define PHY_ANLPARNP_TOGGLE (1<<11) +#define PHY_ANLPARNP_CDE_MASK (0x03ff) +#define PHY_ANER (0x06) +#define PHY_ANER_PDF (1<<4) +#define PHY_ANER_LP_NP_ABLE (1<<3) +#define PHY_ANER_NP_ABLE (1<<2) +#define PHY_ANER_PAGE_RX (1<<1) +#define PHY_ANER_LP_AN_ABLE (1<<0) +#define PHY_ANNPTR (0x07) +#define PHY_ANNPTR_NP (1<<15) +#define PHY_ANNPTR_MP (1<<13) +#define PHY_ANNPTR_ACK2 (1<<12) +#define PHY_ANNPTR_TOG_TX (1<<11) +#define PHY_ANNPTR_CDE_MASK (0x03ff) +#define PHY_PHYSTS (0x10) +#define PHY_PHYSTS_MDIX_MDE (1<<14) +#define PHY_PHYSTS_RCV_ERRL (1<<13) +#define PHY_PHYSTS_POLSTAT (1<<12) +#define PHY_PHYSTS_FCSL (1<<11) +#define PHY_PHYSTS_SD (1<<10) +#define PHY_PHYSTS_DESCL (1<<9) +#define PHY_PHYSTS_PGREC (1<<8) +#define PHY_PHYSTS_MIIIRQ (1<<7) +#define PHY_PHYSTS_REM_FLT (1<<6) +#define PHY_PHYSTS_JABBDET (1<<5) +#define PHY_PHYSTS_AN_CMP (1<<4) +#define PHY_PHYSTS_LOOPBACK (1<<3) +#define PHY_PHYSTS_DUPLEX (1<<2) +#define PHY_PHYSTS_SPEED (1<<1) +#define PHY_PHYSTS_LINK (1<<0) +#define PHY_MICR (0x11) +#define PHY_MICR_TINT (1<<2) +#define PHY_MICR_INTEN (1<<1) +#define PHY_MICR_INT_OE (1<<0) +#define PHY_MISR (0x12) +#define PHY_MISR_ED_INT (1<<14) +#define PHY_MISR_LINK_INT (1<<13) +#define PHY_MISR_SPD_INT (1<<12) +#define PHY_MISR_DUP_INT (1<<11) +#define PHY_MISR_ANC_INT (1<<10) +#define PHY_MISR_FHF_INT (1<<9) +#define PHY_MISR_RHF_INT (1<<8) +#define PHY_MISR_ED_INT_EN (1<<6) +#define PHY_MISR_LINK_INT_EN (1<<5) +#define PHY_MISR_SPD_INT_EN (1<<4) +#define PHY_MISR_DUP_INT_EN (1<<3) +#define PHY_MISR_ANC_INT_EN (1<<2) +#define PHY_MISR_FHF_INT_EN (1<<1) +#define PHY_MISR_RHF_INT_EN (1<<0) +#define PHY_FCSCR (0x14) +#define PHY_RECR (0x15) +#define PHY_PCSR (0x16) +#define PHY_PCSR_TQ_EN (1<<10) +#define PHY_PCSR_SDFPMA (1<<9) +#define PHY_PCSR_SD_OPT (1<<8) +#define PHY_PCSR_DESC_TIME (1<<7) +#define PHY_PCSR_F_100_OK (1<<5) +#define PHY_PCSR_NRZI_BYPASS (1<<2) +#define PHY_RBR (0x17) +#define PHY_RBR_RMII_MODE (1<<5) +#define PHY_RBR_RMII_REV1_0 (1<<4) +#define PHY_RBR_RX_OVF_STS (1<<3) +#define PHY_RBR_RX_UNF_STS (1<<2) +#define PHY_RBR_ELAST_BUF1 (1<<1) +#define PHY_RBR_ELAST_BUF0 (1<<0) +#define PHY_LEDCR (0x18) +#define PHY_LEDCR_DRV_SPDLED (1<<5) +#define PHY_LEDCR_DRV_LNKLED (1<<4) +#define PHY_LEDCR_DRV_ACTLED (1<<3) +#define PHY_LEDCR_SPDLED (1<<2) +#define PHY_LEDCR_LNKLED (1<<1) +#define PHY_LEDCR_ACTLED (1<<0) +#define PHY_PHYCR (0x19) +#define PHY_PHYCR_MDIX_EN (1<<15) +#define PHY_PHYCR_FORCE_MDIX (1<<14) +#define PHY_PHYCR_PAUSE_RX (1<<13) +#define PHY_PHYCR_PAUSE_TX (1<<12) +#define PHY_PHYCR_BIST_FE (1<<11) +#define PHY_PHYCR_PSR_15 (1<<10) +#define PHY_PHYCR_BIST_STATUS (1<<9) +#define PHY_PHYCR_BIST_START (1<<8) +#define PHY_PHYCR_BP_STRETCH (1<<7) +#define PHY_PHYCR_LED_CNFG1 (1<<6) +#define PHY_PHYCR_LED_CNFG0 (1<<5) +#define PHY_PHYCR_ADDR4 (1<<4) +#define PHY_PHYCR_ADDR3 (1<<3) +#define PHY_PHYCR_ADDR2 (1<<2) +#define PHY_PHYCR_ADDR1 (1<<1) +#define PHY_PHYCR_ADDR0 (1<<0) +#define PHY_10BTSCR (0x1A) +#define PHY_10BTSCR_SERIAL (1<<15) +#define PHY_10BTSCR_SQ_MASK (0x07) +#define PHY_10BTSCR_SQ_SHIFT (9) +#define PHY_10BTSCR_LP_10_DIS (1<<8) +#define PHY_10BTSCR_LP_DIS (1<<7) +#define PHY_10BTSCR_FLINK_10 (1<<1) +#define PHY_10BTSCR_POL (1<<4) +#define PHY_10BTSCR_HB_DIS (1<<1) +#define PHY_10BTSCR_JAB_DIS (1<<0) +#define PHY_CDCTRL1 (0x1B) +#define PHY_EDCR (0x1D) + +#endif /* _DP83848PHY_H */ diff --git a/bsps/lm32/shared/net/network.c b/bsps/lm32/shared/net/network.c new file mode 100644 index 0000000000..2bc518ef25 --- /dev/null +++ b/bsps/lm32/shared/net/network.c @@ -0,0 +1,319 @@ +/* + * RTEMS driver for Minimac2 ethernet IP-core of Milkymist SoC + * + * 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. + * + * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) + * Telecom SudParis, France + * Copyright (C) 2011 Sebastien Bourdeauducq + */ + +#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <bsp.h> +#include <bsp/irq-generic.h> +#include <stdio.h> +#include <string.h> +#include <rtems/bspIo.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/status-checks.h> +#include <sys/param.h> +#include <sys/mbuf.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <net/if.h> +#include <net/ethernet.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <rtems.h> +#include "bspopts.h" +#include "../include/system_conf.h" +#include "network.h" + +#define CTS_EVENT RTEMS_EVENT_1 +#define RX_EVENT RTEMS_EVENT_1 +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +static struct arpcom arpcom; +static rtems_id rx_daemon_id; +static rtems_id tx_daemon_id; + +static void minimac_init(void *arg); +static int minimac_ioctl(struct ifnet *ifp, ioctl_command_t command, + caddr_t data); +static void minimac_start(struct ifnet *ifp); + +static void rx_daemon(void *arg); +static void tx_daemon(void *arg); +static rtems_isr rx_interrupt_handler(rtems_vector_number vector); +static rtems_isr tx_interrupt_handler(rtems_vector_number vector); + +static bool validate_mac(const char *m) +{ + int i; + + for(i=0;i<6;i++) + if((m[i] != 0x00) && (m[i] != 0xff)) + return true; + return false; +} + +static const char *get_mac_address(void) +{ + const char *flash_mac = (const char *)FLASH_OFFSET_MAC_ADDRESS; + static const char fallback_mac[6] = { 0x10, 0xe2, 0xd5, 0x00, 0x00, 0x00 }; + + if(validate_mac(flash_mac)) + return flash_mac; + else { + printk("Warning: using fallback MAC address\n"); + return fallback_mac; + } +} + +int rtems_minimac_driver_attach(struct rtems_bsdnet_ifconfig *config, + int attaching) +{ + struct ifnet *ifp; + rtems_isr_entry dummy; + int i; + static int registered; + uint8_t *tx_buffer = (uint8_t *)MINIMAC_TX_BASE; + + if(!attaching) { + printk("Minimac driver cannot be detached.\n"); + return 0; + } + + ifp = &(arpcom.ac_if); + + if(registered) { + printk("Minimac driver already in use.\n"); + return 0; + } + registered = 1; + + memcpy(arpcom.ac_enaddr, get_mac_address(), 6); + ifp->if_mtu = ETHERMTU; + ifp->if_unit = 0; + ifp->if_name = "minimac"; + ifp->if_init = minimac_init; + ifp->if_ioctl = minimac_ioctl; + ifp->if_start = minimac_start; + ifp->if_output = ether_output; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + + if_attach(ifp); + ether_ifattach(ifp); + + rx_daemon_id = rtems_bsdnet_newproc("mrxd", 4096, rx_daemon, NULL); + tx_daemon_id = rtems_bsdnet_newproc("mtxd", 4096, tx_daemon, NULL); + rtems_interrupt_catch(rx_interrupt_handler, MM_IRQ_ETHRX, &dummy); + rtems_interrupt_catch(tx_interrupt_handler, MM_IRQ_ETHTX, &dummy); + + MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_LOADED); + MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_LOADED); + + for(i=0;i<7; i++) + tx_buffer[i] = 0x55; + tx_buffer[7] = 0xd5; + MM_WRITE(MM_MINIMAC_SETUP, 0); + rtems_bsdnet_event_send(tx_daemon_id, CTS_EVENT); + + bsp_interrupt_vector_enable(MM_IRQ_ETHRX); + bsp_interrupt_vector_enable(MM_IRQ_ETHTX); + + return 1; +} + +static void minimac_start(struct ifnet *ifp) +{ + rtems_bsdnet_event_send(tx_daemon_id, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +} + +static void minimac_init(void *arg) +{ + struct ifnet *ifp = &arpcom.ac_if; + ifp->if_flags |= IFF_RUNNING; +} + +static void minimac_stop(void) +{ + struct ifnet *ifp = &arpcom.ac_if; + ifp->if_flags &= ~IFF_RUNNING; +} + +static int minimac_ioctl(struct ifnet *ifp, ioctl_command_t command, + caddr_t data) +{ + int error; + + 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: + minimac_stop(); + break; + case IFF_UP: + minimac_init(NULL); + break; + case IFF_UP | IFF_RUNNING: + minimac_stop(); + minimac_init(NULL); + break; + default: + break; + } + break; + + default: + error = EINVAL; + break; + } + return error; +} + + +static rtems_isr rx_interrupt_handler(rtems_vector_number vector) +{ + /* Deassert IRQ line. + * The RX daemon will then read all the slots we marked as empty. + */ + if(MM_READ(MM_MINIMAC_STATE0) == MINIMAC_STATE_PENDING) + MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_EMPTY); + if(MM_READ(MM_MINIMAC_STATE1) == MINIMAC_STATE_PENDING) + MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_EMPTY); + + rtems_bsdnet_event_send(rx_daemon_id, RX_EVENT); + + lm32_interrupt_ack(1 << MM_IRQ_ETHRX); +} + +static void receive_packet(uint8_t *buffer, int length) +{ + struct ifnet *ifp = &arpcom.ac_if; + struct mbuf *m; + struct ether_header *eh; + uint32_t computed_crc, net_crc; + + if(length < 64) { + printk("Warning: Ethernet packet too short\n"); + return; + } + + length -= 4; /* strip CRC */ + net_crc = ((uint32_t)buffer[length]) + | ((uint32_t)buffer[length+1] << 8) + | ((uint32_t)buffer[length+2] << 16) + | ((uint32_t)buffer[length+3] << 24); + length -= 8; /* strip preamble */ + computed_crc = ether_crc32_le(&buffer[8], length) ^ 0xffffffff; + if(computed_crc == net_crc) { + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + length -= sizeof(struct ether_header); /* strip Ethernet header */ + memcpy(m->m_data, &buffer[8+sizeof(struct ether_header)], length); + m->m_len = m->m_pkthdr.len = length; + m->m_pkthdr.rcvif = ifp; + eh = (struct ether_header *)&buffer[8]; + ether_input(ifp, eh, m); + } else + printk("Ethernet CRC error: got %08x expected %08x (len=%d)\n", + net_crc, computed_crc, length); +} + +static void rx_daemon(void *arg) +{ + rtems_event_set events; + + while(1) { + rtems_bsdnet_event_receive(RX_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); + + if(MM_READ(MM_MINIMAC_STATE0) == MINIMAC_STATE_EMPTY) { + receive_packet((uint8_t *)MINIMAC_RX0_BASE, MM_READ(MM_MINIMAC_COUNT0)); + MM_WRITE(MM_MINIMAC_STATE0, MINIMAC_STATE_LOADED); + } + if(MM_READ(MM_MINIMAC_STATE1) == MINIMAC_STATE_EMPTY) { + receive_packet((uint8_t *)MINIMAC_RX1_BASE, MM_READ(MM_MINIMAC_COUNT1)); + MM_WRITE(MM_MINIMAC_STATE1, MINIMAC_STATE_LOADED); + } + } +} + +/* RTEMS apparently doesn't support m_length() ... */ +static int copy_mbuf_chain(struct mbuf *m, uint8_t *target) +{ + int len; + + len = 0; + while(m != NULL) { + if(m->m_len > 0) { + m_copydata(m, 0, m->m_len, (caddr_t)(target + len)); + len += m->m_len; + } + m = m->m_next; + } + return len; +} + +static void send_packet(struct ifnet *ifp, struct mbuf *m) +{ + unsigned int len; + unsigned int crc; + uint8_t *tx_buffer = (uint8_t *)(MINIMAC_TX_BASE+8); + + len = copy_mbuf_chain(m, tx_buffer); + for(;len<60;len++) + tx_buffer[len] = 0x00; // Padding + + crc = ether_crc32_le(tx_buffer, len) ^ 0xffffffff; + + tx_buffer[len] = crc & 0xff; + tx_buffer[len+1] = (crc & 0xff00) >> 8; + tx_buffer[len+2] = (crc & 0xff0000) >> 16; + tx_buffer[len+3] = crc >> 24; + + len += 4; // We add 4 bytes of CRC32 + + MM_WRITE(MM_MINIMAC_TXCOUNT, len + 8); +} + +static rtems_isr tx_interrupt_handler(rtems_vector_number vector) +{ + lm32_interrupt_ack(1 << MM_IRQ_ETHTX); + rtems_bsdnet_event_send(tx_daemon_id, CTS_EVENT); +} + +static void tx_daemon(void *arg) +{ + struct ifnet *ifp = &arpcom.ac_if; + rtems_event_set events; + struct mbuf *m; + + while(1) { + rtems_bsdnet_event_receive(START_TRANSMIT_EVENT, + RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + while(1) { + IF_DEQUEUE(&ifp->if_snd, m); + if(m == NULL) + break; + rtems_bsdnet_event_receive(CTS_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, &events); + send_packet(ifp, m); + m_freem(m); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} diff --git a/bsps/lm32/shared/net/network.h b/bsps/lm32/shared/net/network.h new file mode 100644 index 0000000000..7961c8413c --- /dev/null +++ b/bsps/lm32/shared/net/network.h @@ -0,0 +1,31 @@ +/** + * @file + * @ingroup lm32_milkymist_network lm32_milkymist_shared + * @brief Driver for Minimac ethernet + */ + +/* network.h + * + * RTEMS driver for Minimac ethernet IP-core of Milkymist SoC + * + * 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. + * + * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) + * Telecom SudParis, France + */ + +/** + * @defgroup lm32_milkymist_network Minimac ethernet driver + * @ingroup lm32_milkymist_shared + * @brief Driver for Minimac ethernet IP-core of Milkymist SoC + * @{ + */ + +#ifndef __MILKYMIST_NETWORKING_H_ +#define __MILKYMIST_NETWORKING_H_ + +int rtems_minimac_driver_attach (struct rtems_bsdnet_ifconfig *, int); + +#endif 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); +} + diff --git a/bsps/lm32/shared/net/tsmac.h b/bsps/lm32/shared/net/tsmac.h new file mode 100644 index 0000000000..bb2d3b4451 --- /dev/null +++ b/bsps/lm32/shared/net/tsmac.h @@ -0,0 +1,172 @@ +/** + * @file + * @ingroup lm32_tsmac + * @brief LatticeMico32 TSMAC (Tri-Speed MAC) definitions. + */ + +/* + * 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 + */ + +/** + * @defgroup lm32_tsmac LM32 TSMAC + * @ingroup lm32_shared + * @brief LatticeMico32 TSMAC (Tri-Speed MAC) definitions. + * @{ + */ + +#ifndef _BSPTSMAC_H +#define _BSPTSMAC_H + +/* FIFO Registers */ + +#define LM32_TSMAC_RX_LEN_FIFO (0x000) +#define LM32_TSMAC_RX_DATA_FIFO (0x004) +#define LM32_TSMAC_TX_LEN_FIFO (0x008) +#define LM32_TSMAC_TX_DATA_FIFO (0x00C) + +/* Control and Status Registers */ + +#define LM32_TSMAC_VERID (0x100) +#define LM32_TSMAC_INTR_SRC (0x104) +#define INTR_RX_SMRY (0x00020000) +#define INTR_TX_SMRY (0x00010000) +#define INTR_RX_FIFO_FULL (0x00001000) +#define INTR_RX_ERROR (0x00000800) +#define INTR_RX_FIFO_ERROR (0x00000400) +#define INTR_RX_FIFO_ALMOST_FULL (0x00000200) +#define INTR_RX_PKT_RDY (0x00000100) +#define INTR_TX_FIFO_FULL (0x00000010) +#define INTR_TX_DISCFRM (0x00000008) +#define INTR_TX_FIFO_ALMOST_EMPTY (0x00000004) +#define INTR_TX_FIFO_ALMOST_FULL (0x00000002) +#define INTR_TX_PKT_SENT (0x00000001) +#define LM32_TSMAC_INTR_ENB (0x108) +#define INTR_ENB (0x00040000) +#define LM32_TSMAC_RX_STATUS (0x10C) +#define STAT_RX_FIFO_FULL (0x00000010) +#define STAT_RX_ERROR (0x00000008) +#define STAT_RX_FIFO_ERROR (0x00000004) +#define STAT_RX_FIFO_ALMOST_FULL (0x00000002) +#define STAT_RX_PKT_RDY (0x00000001) +#define LM32_TSMAC_TX_STATUS (0x110) +#define STAT_TX_FIFO_FULL (0x00000010) +#define STAT_TX_DISCFRM (0x00000008) +#define STAT_TX_FIFO_ALMOST_EMPTY (0x00000004) +#define STAT_TX_FIFO_ALMOST_FULL (0x00000002) +#define STAT_TX_PKT_SENT (0x00000001) +#define LM32_TSMAC_RX_FRAMES_CNT (0x114) +#define LM32_TSMAC_TX_FRAMES_CNT (0x118) +#define LM32_TSMAC_RX_FIFO_TH (0x11C) +#define LM32_TSMAC_TX_FIFO_TH (0x120) +#define LM32_TSMAC_SYS_CTL (0x124) +#define SYS_CTL_TX_FIFO_FLUSH (0x00000010) +#define SYS_CTL_RX_FIFO_FLUSH (0x00000008) +#define SYS_CTL_TX_SNDPAUSREQ (0x00000004) +#define SYS_CTL_TX_FIFOCTRL (0x00000002) +#define SYS_CTL_IGNORE_NEXT_PKT (0x00000001) +#define LM32_TSMAC_PAUSE_TMR (0x128) + +/* Tri-Speed MAC Registers */ + +#define LM32_TSMAC_MAC_REGS_DATA (0x200) +#define LM32_TSMAC_MAC_REGS_ADDR_RW (0x204) +#define REGS_ADDR_WRITE (0x80000000) +#define LM32_TSMAC_MODE_BYTE0 (0x000) +#define MODE_TX_EN (1<<3) +#define MODE_RX_EN (1<<2) +#define MODE_FC_EN (1<<1) +#define MODE_GBIT_EN (1<<0) +#define LM32_TSMAC_TX_RX_CTL_BYTE0 (0x002) +#define TX_RX_CTL_RECEIVE_SHORT (1<<8) +#define TX_RX_CTL_RECEIVE_BRDCST (1<<7) +#define TX_RX_CTL_DIS_RTRY (1<<6) +#define TX_RX_CTL_HDEN (1<<5) +#define TX_RX_CTL_RECEIVE_MLTCST (1<<4) +#define TX_RX_CTL_RECEIVE_PAUSE (1<<3) +#define TX_RX_CTL_TX_DIS_FCS (1<<2) +#define TX_RX_CTL_DISCARD_FCS (1<<1) +#define TX_RX_CTL_PRMS (1<<0) +#define LM32_TSMAC_MAX_PKT_SIZE_BYTE0 (0x004) +#define LM32_TSMAC_IPG_VAL_BYTE0 (0x008) +#define LM32_TSMAC_MAC_ADDR_0_BYTE0 (0x00A) +#define LM32_TSMAC_MAC_ADDR_1_BYTE0 (0x00C) +#define LM32_TSMAC_MAC_ADDR_2_BYTE0 (0x00E) +#define LM32_TSMAC_TX_RX_STS_BYTE0 (0x012) +#define TX_RX_STS_RX_IDLE (1<<10) +#define TX_RX_STS_TAGGED_FRAME (1<<9) +#define TX_RX_STS_BRDCST_FRAME (1<<8) +#define TX_RX_STS_MULTCST_FRAME (1<<7) +#define TX_RX_STS_IPG_SHRINK (1<<6) +#define TX_RX_STS_SHORT_FRAME (1<<5) +#define TX_RX_STS_LONG_FRAME (1<<4) +#define TX_RX_STS_ERROR_FRAME (1<<3) +#define TX_RX_STS_CRC (1<<2) +#define TX_RX_STS_PAUSE_FRAME (1<<1) +#define TX_RX_STS_TX_IDLE (1<<0) +#define LM32_TSMAC_GMII_MNG_CTL_BYTE0 (0x014) +#define GMII_MNG_CTL_CMD_FIN (1<<14) +#define GMII_MNG_CTL_READ_PHYREG (0) +#define GMII_MNG_CTL_WRITE_PHYREG (1<<13) +#define GMII_MNG_CTL_PHY_ADD_MASK (0x001f) +#define GMII_MNG_CTL_PHY_ADD_SHIFT (8) +#define GMII_MNG_CTL_REG_ADD_MASK (0x001f) +#define GMII_MNG_CTL_REG_ADD_SHIFT (0) +#define LM32_TSMAC_GMII_MNG_DAT_BYTE0 (0x016) +#define LM32_TSMAC_MLT_TAB_0_BYTE0 (0x022) +#define LM32_TSMAC_MLT_TAB_1_BYTE0 (0x024) +#define LM32_TSMAC_MLT_TAB_2_BYTE0 (0x026) +#define LM32_TSMAC_MLT_TAB_3_BYTE0 (0x028) +#define LM32_TSMAC_MLT_TAB_4_BYTE0 (0x02A) +#define LM32_TSMAC_MLT_TAB_5_BYTE0 (0x02C) +#define LM32_TSMAC_MLT_TAB_6_BYTE0 (0x02E) +#define LM32_TSMAC_MLT_TAB_7_BYTE0 (0x030) +#define LM32_TSMAC_VLAN_TAG_BYTE0 (0x032) +#define LM32_TSMAC_PAUS_OP_BYTE0 (0x034) + +/* Receive Statistics Counters */ + +#define LM32_TSMAC_RX_PKT_IGNR_CNT (0x300) +#define LM32_TSMAC_RX_LEN_CHK_ERR_CNT (0x304) +#define LM32_TSMAC_RX_LNG_FRM_CNT (0x308) +#define LM32_TSMAC_RX_SHRT_FRM_CNT (0x30C) +#define LM32_TSMAC_RX_IPG_VIOL_CNT (0x310) +#define LM32_TSMAC_RX_CRC_ERR_CNT (0x314) +#define LM32_TSMAC_RX_OK_PKT_CNT (0x318) +#define LM32_TSMAC_RX_CTL_FRM_CNT (0x31C) +#define LM32_TSMAC_RX_PAUSE_FRM_CNT (0x320) +#define LM32_TSMAC_RX_MULTICAST_CNT (0x324) +#define LM32_TSMAC_RX_BRDCAST_CNT (0x328) +#define LM32_TSMAC_RX_VLAN_TAG_CNT (0x32C) +#define LM32_TSMAC_RX_PRE_SHRINK_CNT (0x330) +#define LM32_TSMAC_RX_DRIB_NIB_CNT (0x334) +#define LM32_TSMAC_RX_UNSUP_OPCD_CNT (0x338) +#define LM32_TSMAC_RX_BYTE_CNT (0x33C) + +/* Transmit Statistics Counters */ + +#define LM32_TSMAC_TX_UNICAST_CNT (0x400) +#define LM32_TSMAC_TX_PAUSE_FRM_CNT (0x404) +#define LM32_TSMAC_TX_MULTICAST_CNT (0x408) +#define LM32_TSMAC_TX_BRDCAST_CNT (0x40C) +#define LM32_TSMAC_TX_VLAN_TAG_CNT (0x410) +#define LM32_TSMAC_TX_BAD_FCS_CNT (0x414) +#define LM32_TSMAC_TX_JUMBO_CNT (0x418) +#define LM32_TSMAC_TX_BYTE_CNT (0x41C) + +#ifdef CPU_U32_FIX +void ipalign(struct mbuf *m); +#endif + +#endif /* _BSPTSMAC_H */ +/** @} */ |