diff options
Diffstat (limited to 'c/src/lib/libbsp/lm32/shared/milkymist_networking')
3 files changed, 563 insertions, 0 deletions
diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_networking/mm_crc32.c b/c/src/lib/libbsp/lm32/shared/milkymist_networking/mm_crc32.c new file mode 100644 index 0000000000..6489c005d9 --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_networking/mm_crc32.c @@ -0,0 +1,82 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * COPYRIGHT (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * $Id$ + * + */ + +const unsigned int crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +unsigned int mm_ether_crc32(const unsigned char *buffer, unsigned int len) +{ + unsigned int crc; + crc = 0; + crc = crc ^ 0xffffffffL; + while(len >= 8) { + DO8(buffer); + len -= 8; + } + if(len) do { + DO1(buffer); + } while(--len); + return crc ^ 0xffffffffL; +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c new file mode 100644 index 0000000000..9899777d1b --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.c @@ -0,0 +1,401 @@ +/* + * 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.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) + * Telecom SudParis, France + */ + + +#include <bsp.h> +#include "../include/system_conf.h" +#include "bspopts.h" +#include <stdio.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 <rtems.h> +#include "network.h" + +unsigned int mm_ether_crc32(const unsigned char *buffer, unsigned int len); +static char rxbuff0[ETHERNET_FRAME_LENGTH] __attribute__((aligned (4))); +static char rxbuff1[ETHERNET_FRAME_LENGTH] __attribute__((aligned (4))); +static char rxbuff2[ETHERNET_FRAME_LENGTH] __attribute__((aligned (4))); +static char rxbuff3[ETHERNET_FRAME_LENGTH] __attribute__((aligned (4))); + +static char *rxbuffs[4] = {rxbuff0, rxbuff1, rxbuff2, rxbuff3}; + +static struct minimac_softc minimac_softc; + +static uint32_t rx_slot_state[4] = {MM_MINIMAC_STATE0, MM_MINIMAC_STATE1, + MM_MINIMAC_STATE2, MM_MINIMAC_STATE3}; + +static uint32_t rx_slot_addr[4] = {MM_MINIMAC_ADDR0, MM_MINIMAC_ADDR1, + MM_MINIMAC_ADDR2, MM_MINIMAC_ADDR3}; + +static uint32_t rx_slot_count[4] = {MM_MINIMAC_COUNT0, MM_MINIMAC_COUNT1, + MM_MINIMAC_COUNT2, MM_MINIMAC_COUNT3}; +#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 + +static inline int minimac_read(unsigned int reg) +{ + return *((int*)(reg)); +} + +static inline void minimac_write(unsigned int reg, int value) +{ + *((int*)reg) = value; +} + +int rtems_minimac_driver_attach (struct rtems_bsdnet_ifconfig *config, + int attaching) +{ + struct minimac_softc *sc; + struct ifnet *ifp; + + + if (!attaching) { + printk ("MINIMAC driver cannot be detached.\n"); + return 0; + } + + sc = &minimac_softc; + ifp = &(sc->arpcom.ac_if); + + if (sc->registered) { + printk ("Driver already in use.\n"); + return 0; + } + + sc->registered = 1; + + /* + * Mac address of Milkymist One board is 1 by default + */ + + sc->arpcom.ac_enaddr[0] = 0x00; + sc->arpcom.ac_enaddr[1] = 0x23; + sc->arpcom.ac_enaddr[2] = 0x8b; + sc->arpcom.ac_enaddr[3] = 0x47; + sc->arpcom.ac_enaddr[4] = 0x86; + sc->arpcom.ac_enaddr[5] = 0x20; + ifp->if_softc = sc; + 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); + printk("[minimac] Ethernet driver attached\n"); + return 1; +} + +static void minimac_start(struct ifnet *ifp) +{ + struct minimac_softc *sc = ifp->if_softc; + rtems_event_send (sc->txDaemonTid, START_TRANSMIT_EVENT); + ifp->if_flags |= IFF_OACTIVE; +// printk("[minimac] start();\n"); +} + +/* + * Initialize and start the device + */ +static void minimac_init (void *arg) +{ + struct minimac_softc *sc = arg; + struct ifnet *ifp = &sc->arpcom.ac_if; + unsigned char j; + if (sc->txDaemonTid == 0) { + sc->txDaemonTid = rtems_bsdnet_newproc ("MINIMACtx", 4096, minimac_txDaemon, sc); + sc->rxDaemonTid = rtems_bsdnet_newproc ("MINIMACrx", 4096, minimac_rxDaemon, sc); + set_vector(minimac_rx_interrupt_handler, IRQ_ETHRX, 1); + set_vector(minimac_tx_interrupt_handler, IRQ_ETHTX, 1); + lm32_interrupt_unmask(MM_ETHRX_IRQMASK); + lm32_interrupt_unmask(MM_ETHTX_IRQMASK); + } + + /* + * Tell the world that we're running. + */ + ifp->if_flags |= IFF_RUNNING; + + /* + * Start the receiver and transmitter + */ + + lm32_interrupt_ack( MM_ETHTX_IRQMASK | MM_ETHRX_IRQMASK ); + minimac_write(MM_MINIMAC_TXREMAINING, 0); + + for (j = 0 ; j < NB_RX_SLOTS ; j++) { + minimac_write(rx_slot_addr[j], (unsigned int)rxbuffs[j]); + minimac_write(rx_slot_state[j], MINIMAC_STATE_LOADED); + } + + + minimac_write(MM_MINIMAC_SETUP, 0); + rtems_event_send(sc->rxDaemonTid, INTERRUPT_EVENT); +} + +static void minimac_stop (struct minimac_softc *sc) +{ + struct ifnet *ifp = &sc->arpcom.ac_if; + unsigned char j; + ifp->if_flags &= ~IFF_RUNNING; + + /* + * Shuts down receiver and transmitter + */ + for (j = 0 ; j < NB_RX_SLOTS ; j++) + minimac_write(rx_slot_state[j], MINIMAC_STATE_EMPTY); + minimac_write(MM_MINIMAC_TXREMAINING, 0); + minimac_write(MM_MINIMAC_SETUP, MINIMAC_SETUP_RXRST | MINIMAC_SETUP_TXRST); +} + +static int minimac_ioctl(struct ifnet *ifp, ioctl_command_t command, caddr_t data) +{ + + struct minimac_softc *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: + minimac_stop (sc); + break; + + case IFF_UP: + minimac_init (sc); + break; + + case IFF_UP | IFF_RUNNING: + minimac_stop (sc); + minimac_init (sc); + break; + + default: + break; + } + break; + + case SIO_RTEMS_SHOW_STATS: + minimac_stats (sc); + break; + + /* + * FIXME: All sorts of multicast commands need to be added here! + */ + default: + error = EINVAL; + break; + } + return error; + + +} + +rtems_isr minimac_rx_interrupt_handler(rtems_vector_number vector) +{ + unsigned int ip; + struct minimac_softc *sc = &minimac_softc; + lm32_read_interrupts(ip); + if (ip & MM_ETHRX_IRQMASK) { + lm32_interrupt_mask(MM_ETHRX_IRQMASK); + rtems_event_send(sc->rxDaemonTid, INTERRUPT_EVENT); + sc->rxInterrupts++; // update stats + } +} + +rtems_isr minimac_tx_interrupt_handler(rtems_vector_number vector) +{ + int ip; + struct minimac_softc *sc = &minimac_softc; + lm32_read_interrupts(ip); + if (ip & MM_ETHTX_IRQMASK) { + lm32_interrupt_ack(MM_ETHTX_IRQMASK); + rtems_event_send(sc->txDaemonTid, INTERRUPT_EVENT); + sc->txInterrupts++; // update stats + } +} + + +static void minimac_rxDaemon(void *arg) +{ + struct ifnet *ifp = &minimac_softc.arpcom.ac_if; + rtems_event_set events; + struct minimac_softc *sc = &minimac_softc; + for (;;) { + uint32_t *buf; + int rxlen; + uint8_t j; + struct mbuf *m; + struct ether_header *eh; + rtems_bsdnet_event_receive( RTEMS_ALL_EVENTS, + RTEMS_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &events); + if(minimac_read(MM_MINIMAC_SETUP) & MINIMAC_SETUP_RXRST ) { + printk("Minimac RX FIFO overflow!\n"); + minimac_write(MM_MINIMAC_SETUP, 0); + lm32_interrupt_ack(MM_ETHRX_IRQMASK); + lm32_interrupt_unmask(MM_ETHRX_IRQMASK); + sc->txFifoFull++; // update stats + } + + for (j = 0 ; j < NB_RX_SLOTS ; j++) { + if (minimac_read(rx_slot_state[j]) == MINIMAC_STATE_PENDING) { + asm volatile( /* Invalidate Level-1 data cache */ + "wcsr DCC, r0\n" + "nop\n" + ); + rxlen = minimac_read(rx_slot_count[j]); + rxlen -= 8; // we drop the preamble + MGETHDR(m, M_WAIT, MT_DATA); + MCLGET(m, M_WAIT); + m->m_pkthdr.rcvif = ifp; + buf = (uint32_t *) mtod(m, uint32_t*); + memcpy(buf, (uint8_t *)minimac_read(rx_slot_addr[j]) + 8, rxlen); + m->m_len = m->m_pkthdr.len = rxlen - sizeof(uint32_t) - sizeof(struct ether_header); + + minimac_write(rx_slot_state[j], MINIMAC_STATE_EMPTY); + minimac_write(rx_slot_state[j], MINIMAC_STATE_LOADED); + eh = mtod(m, struct ether_header*); + m->m_data += sizeof(struct ether_header); +#ifdef CPU_U32_FIX + ipalign(m); +#endif + ether_input(ifp, eh, m); + } + } + lm32_interrupt_ack(MM_ETHRX_IRQMASK); // we ack once for all the rx interruptions + lm32_interrupt_unmask(MM_ETHRX_IRQMASK); + } +} +static void minimac_txDaemon(void *arg) +{ + struct ifnet *ifp = &minimac_softc.arpcom.ac_if; + rtems_event_set events; + struct mbuf *m; + int txq; + + for (;;) { + rtems_bsdnet_event_receive (START_TRANSMIT_EVENT | INTERRUPT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_NO_TIMEOUT, &events); + for (;;) { + txq = 2048; + + if (txq < ifp->if_mtu) + break; + + IF_DEQUEUE(&ifp->if_snd, m); + + if (!m) + break; + minimac_sendpacket(ifp, m); + m_freem(m); + } + ifp->if_flags &= ~IFF_OACTIVE; + } +} + +static void minimac_stats(struct minimac_softc *sc) +{ + +} + + +static void minimac_sendpacket(struct ifnet *ifp, struct mbuf *m) +{ + struct mbuf *nm = m; + struct minimac_softc *sc = &minimac_softc; + unsigned int len = 0; + struct mm_packet p; + unsigned int crc; + uint8_t i; + for (i = 0 ; i < 7 ; i++) // Preamble + p.preamble[i] = 0x55; + p.preamble[7] = 0xd5; + + do + { + unsigned int mlen; + mlen = nm->m_len; + if (nm->m_len > 0) { + m_copydata(nm, 0, mlen, p.raw_data + len); + len += nm->m_len; + } + + } while ( (nm = nm->m_next) != 0 ); + for ( ; len < 60 ; len++) + p.raw_data[len] = 0x00; // Padding + + crc = mm_ether_crc32((uint8_t *)p.raw_data, len); // CRC32 + + p.raw_data[len] = crc & 0xff; + p.raw_data[len+1] = (crc & 0xff00) >> 8; + p.raw_data[len+2] = (crc & 0xff0000) >> 16; + p.raw_data[len+3] = crc >> 24; + + len += 4; // We add 4 bytes of CRC32 + + if (len + 8 < 64) { + printk("[minimac] Packet is too small !\n"); + sc->txErrors++; // update stats + return; + } + + minimac_write(MM_MINIMAC_TXADR, (unsigned int)&p); + minimac_write(MM_MINIMAC_TXREMAINING, (unsigned int)(len + 8)); +} diff --git a/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h new file mode 100644 index 0000000000..6d967c5b6c --- /dev/null +++ b/c/src/lib/libbsp/lm32/shared/milkymist_networking/network.h @@ -0,0 +1,80 @@ +/* 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.com/license/LICENSE. + * + * $Id$ + * + * COPYRIGHT (c) Yann Sionneau <yann.sionneau@telecom-sudparis.eu> (GSoC 2010) + * Telecom SudParis, France + */ + + +#ifndef _MM_NETWORKING_H_ +#define _MM_NETWORKING_H_ + +#include "../include/system_conf.h" + +#define IRQ_ETHRX 11 +#define IRQ_ETHTX 12 + +#define INTERRUPT_EVENT RTEMS_EVENT_1 +#define START_TRANSMIT_EVENT RTEMS_EVENT_2 + +#define MINIMAC_STATE_EMPTY (0x0) +#define MINIMAC_STATE_LOADED (0x1) +#define MINIMAC_STATE_PENDING (0x2) + +#define MINIMAC_SETUP_RXRST (0x1) +#define MINIMAC_SETUP_TXRST (0x2) + +#define NB_RX_SLOTS 4 + +#define MM_ETHTX_IRQMASK (1 << IRQ_ETHTX) +#define MM_ETHRX_IRQMASK (1 << IRQ_ETHRX) +#define ETHERNET_FRAME_LENGTH 1532 + +struct mm_packet { + unsigned char preamble[8]; + char raw_data[MLEN]; +} __attribute__((aligned(4), packed)); + +struct minimac_softc { + + struct arpcom arpcom; + uint8_t registered; + + /* + * Statistics + */ + + rtems_id rxDaemonTid; + rtems_id txDaemonTid; + + unsigned long int rxInterrupts; + unsigned long int txInterrupts; + unsigned long int rxedPackets; + unsigned long int txFifoFull; + unsigned long int txErrors; +}; + +int rtems_minimac_driver_attach (struct rtems_bsdnet_ifconfig *, int); + +static void minimac_start(struct ifnet *); +static void minimac_init(void *); +static int minimac_ioctl(struct ifnet *, ioctl_command_t, caddr_t); +static void minimac_stop(struct minimac_softc *); + +static void minimac_txDaemon(void *); +static void minimac_rxDaemon(void *); +static void minimac_sendpacket(struct ifnet *, struct mbuf *); + +static rtems_isr minimac_rx_interrupt_handler (rtems_vector_number); +static rtems_isr minimac_tx_interrupt_handler (rtems_vector_number); + +static void minimac_stats(struct minimac_softc *); + +#endif |