diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2010-04-30 11:29:29 +0000 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2010-04-30 11:29:29 +0000 |
commit | 7933f8d799e9882fecf8a64128d978a470d061c5 (patch) | |
tree | 015fe559a482be47eb0b5a848b61da724d7e6e2d /c | |
parent | 2010-04-30 Sebastian Huber <sebastian.huber@embedded-brains.de> (diff) | |
download | rtems-7933f8d799e9882fecf8a64128d978a470d061c5.tar.bz2 |
Removed file.
Diffstat (limited to 'c')
-rw-r--r-- | c/src/lib/libbsp/arm/lpc24xx/network/network.c | 1206 |
1 files changed, 0 insertions, 1206 deletions
diff --git a/c/src/lib/libbsp/arm/lpc24xx/network/network.c b/c/src/lib/libbsp/arm/lpc24xx/network/network.c deleted file mode 100644 index 2941aeaf6b..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/network/network.c +++ /dev/null @@ -1,1206 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx - * - * @brief Network driver. - */ - -/* - * Copyright (c) 2008 - * Embedded Brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * rtems@embedded-brains.de - * - * 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. - */ - -#include <errno.h> -#include <inttypes.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <rtems.h> -#include <rtems/rtems_bsdnet.h> -#include <rtems/rtems_mii_ioctl.h> - -#include <sys/param.h> -#include <sys/socket.h> -#include <sys/sockio.h> -#include <sys/mbuf.h> - -#include <net/if.h> -#include <net/if_arp.h> -#include <netinet/in.h> -#include <netinet/if_ether.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> - -#include <bsp.h> -#include <bsp/lpc24xx.h> -#include <bsp/irq.h> -#include <bsp/io.h> -#include <bsp/utility.h> - -#include <rtems/status-checks.h> - -#if MCLBYTES > (2 * 1024) - #error "MCLBYTES to large" -#endif - -#define LPC24XX_ETH_INTERFACE_NUMBER 1 - -/** - * @brief Start address of the Ethernet RAM. - */ -#define LPC24XX_ETH_RAM_START 0x7fe00000U - -/** - * @brief Size of the Ethernet RAM. - */ -#define LPC24XX_ETH_RAM_SIZE (16 * 1024) - -#define LPC24XX_ETH_RAM_END \ - (LPC24XX_ETH_RAM_START + LPC24XX_ETH_RAM_SIZE) - -#define LPC24XX_ETH_TRANSMIT_BUFFER_SIZE 1518 - -#define LPC24XX_ETH_RECEIVE_UNIT_SIZE \ - (ETH_TRANSFER_DESCRIPTOR_SIZE \ - + ETH_RECEIVE_INFO_SIZE \ - + 4) - -#define LPC24XX_ETH_TRANSMIT_UNIT_SIZE \ - (ETH_TRANSFER_DESCRIPTOR_SIZE \ - + ETH_TRANSMIT_STATUS_SIZE \ - + LPC24XX_ETH_TRANSMIT_BUFFER_SIZE) - -#define LPC24XX_ETH_RECEIVE_UNIT_NUMBER 54 - -#define LPC24XX_ETH_TRANSMIT_UNIT_NUMBER 10 - -#define LPC24XX_ETH_RECEIVE_DATA_SIZE \ - (LPC24XX_ETH_RECEIVE_UNIT_NUMBER \ - * LPC24XX_ETH_RECEIVE_UNIT_SIZE) - -#define LPC24XX_ETH_RECEIVE_DATA_START \ - LPC24XX_ETH_RAM_START - -#define LPC24XX_ETH_RECEIVE_DATA_END \ - (LPC24XX_ETH_RECEIVE_DATA_START \ - + LPC24XX_ETH_RECEIVE_DATA_SIZE) - -#define LPC24XX_ETH_TRANSMIT_DATA_SIZE \ - (LPC24XX_ETH_TRANSMIT_UNIT_NUMBER \ - * LPC24XX_ETH_TRANSMIT_UNIT_SIZE) - -#if 1 - -#define LPC24XX_ETH_TRANSMIT_DATA_START \ - LPC24XX_ETH_RECEIVE_DATA_END - -#else - -static char lpc24xx_eth_transmit_buffer [LPC24XX_ETH_TRANSMIT_DATA_SIZE]; - -#define LPC24XX_ETH_TRANSMIT_DATA_START \ - lpc24xx_eth_transmit_buffer - -#endif - -#define LPC24XX_ETH_TRANSMIT_DATA_END \ - (LPC24XX_ETH_TRANSMIT_DATA_START \ - + LPC24XX_ETH_TRANSMIT_DATA_SIZE) - -#if LPC24XX_ETH_TRANSMIT_DATA_END > LPC24XX_ETH_RAM_END && 0 - #error "Ethernet RAM overflow" -#endif - -#define LPC24XX_ETH_RECEIVE_DESC_START \ - LPC24XX_ETH_RECEIVE_DATA_START - -#define LPC24XX_ETH_RECEIVE_INFO_START \ - (LPC24XX_ETH_RECEIVE_DESC_START \ - + LPC24XX_ETH_RECEIVE_UNIT_NUMBER * ETH_TRANSFER_DESCRIPTOR_SIZE) - -#define LPC24XX_ETH_RECEIVE_MBUF_START \ - (LPC24XX_ETH_RECEIVE_INFO_START \ - + LPC24XX_ETH_RECEIVE_UNIT_NUMBER * ETH_RECEIVE_INFO_SIZE) - -#define LPC24XX_ETH_TRANSMIT_DESC_START \ - LPC24XX_ETH_TRANSMIT_DATA_START - -#define LPC24XX_ETH_TRANSMIT_STATUS_START \ - (LPC24XX_ETH_TRANSMIT_DATA_START \ - + LPC24XX_ETH_TRANSMIT_UNIT_NUMBER * ETH_TRANSFER_DESCRIPTOR_SIZE) - -#define LPC24XX_ETH_TRANSMIT_BUFFER_START \ - (LPC24XX_ETH_TRANSMIT_STATUS_START \ - + LPC24XX_ETH_TRANSMIT_UNIT_NUMBER * ETH_TRANSMIT_STATUS_SIZE) - -#define LPC24XX_ETH_EVENT_INITIALIZE RTEMS_EVENT_1 - -#define LPC24XX_ETH_EVENT_START RTEMS_EVENT_2 - -#define LPC24XX_ETH_EVENT_INTERRUPT RTEMS_EVENT_3 - -#define LPC24XX_ETH_INTERRUPT_RECEIVE \ - (ETH_INT_RX_ERROR | ETH_INT_RX_FINISHED | ETH_INT_RX_DONE) - -#define LPC24XX_ETH_INTERRUPT_TRANSMIT \ - (ETH_INT_TX_DONE | ETH_INT_TX_FINISHED | ETH_INT_TX_ERROR) - -#define LPC24XX_ETH_RX_STAT_ERRORS \ - (ETH_RX_STAT_CRC_ERROR \ - | ETH_RX_STAT_SYMBOL_ERROR \ - | ETH_RX_STAT_LENGTH_ERROR \ - | ETH_RX_STAT_ALIGNMENT_ERROR \ - | ETH_RX_STAT_OVERRUN \ - | ETH_RX_STAT_NO_DESCRIPTOR) - -#define LPC24XX_ETH_LAST_FRAGMENT_FLAGS \ - (ETH_TX_CTRL_OVERRIDE \ - | ETH_TX_CTRL_PAD \ - | ETH_TX_CTRL_CRC \ - | ETH_TX_CTRL_INTERRUPT \ - | ETH_TX_CTRL_LAST) - -#ifdef DEBUG - #define LPC24XX_ETH_PRINTF(...) printf(__VA_ARGS__) - #define LPC24XX_ETH_PRINTK(...) printk(__VA_ARGS__) -#else - #define LPC24XX_ETH_PRINTF(...) - #define LPC24XX_ETH_PRINTK(...) -#endif - -typedef enum { - LPC24XX_ETH_NOT_INITIALIZED, - LPC24XX_ETH_INITIALIZED, - LPC24XX_ETH_STARTED, - LPC24XX_ETH_RUNNING -} lpc24xx_eth_state; - -typedef struct { - struct arpcom arpcom; - struct rtems_mdio_info mdio_info; - lpc24xx_eth_state state; - rtems_id receive_task; - rtems_id transmit_task; - unsigned receive_unit_number; - unsigned transmit_unit_number; - unsigned received_frames; - unsigned receive_interrupts; - unsigned transmitted_frames; - unsigned transmit_interrupts; - unsigned receive_overrun_errors; - unsigned receive_fragment_errors; - unsigned receive_crc_errors; - unsigned receive_symbol_errors; - unsigned receive_length_errors; - unsigned receive_alignment_errors; - unsigned receive_no_descriptor_errors; - unsigned receive_fatal_errors; - unsigned transmit_underrun_errors; - unsigned transmit_late_collision_errors; - unsigned transmit_excessive_collision_errors; - unsigned transmit_excessive_defer_errors; - unsigned transmit_no_descriptor_errors; - unsigned transmit_overflow_errors; - unsigned transmit_fatal_errors; -} lpc24xx_eth_driver_entry; - -static lpc24xx_eth_driver_entry lpc24xx_eth_driver_data = { - .state = LPC24XX_ETH_NOT_INITIALIZED, - .receive_task = RTEMS_ID_NONE, - .transmit_task = RTEMS_ID_NONE -}; - -static inline uint32_t lpc24xx_eth_increment( - uint32_t value, - uint32_t cycle -) -{ - if (value < cycle) { - return ++value; - } else { - return 0; - } -} - -static void lpc24xx_eth_reset_filter(void) -{ - MAC_RXFILTERCTRL = 0; - MAC_RXFILTERWOLCLR = 0xcf; - MAC_HASHFILTERL = 0; - MAC_HASHFILTERH = 0; -} - -static void lpc24xx_eth_enable_promiscous_mode(bool enable) -{ - if (enable) { - MAC_RXFILTERCTRL = ETH_RX_FIL_CTRL_ACCEPT_PERFECT - | ETH_RX_FIL_CTRL_ACCEPT_UNICAST - | ETH_RX_FIL_CTRL_ACCEPT_MULTICAST - | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST; - } else { - MAC_RXFILTERCTRL = ETH_RX_FIL_CTRL_ACCEPT_PERFECT - | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST; - } -} - -static void lpc24xx_eth_interrupt_handler(void *arg) -{ - lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg; - rtems_event_set re = 0; - rtems_event_set te = 0; - uint32_t ie = 0; - - /* Get interrupt status */ - uint32_t im = MAC_INTENABLE; - uint32_t is = MAC_INTSTATUS & im; - - /* Check receive interrupts */ - if (IS_FLAG_SET(is, ETH_INT_RX_OVERRUN)) { - re = LPC24XX_ETH_EVENT_INITIALIZE; - ++e->receive_fatal_errors; - } else if (IS_ANY_FLAG_SET(is, LPC24XX_ETH_INTERRUPT_RECEIVE)) { - re = LPC24XX_ETH_EVENT_INTERRUPT; - ie = SET_FLAGS(ie, LPC24XX_ETH_INTERRUPT_RECEIVE); - } - - /* Send events to receive task */ - if (re != 0) { - ++e->receive_interrupts; - (void) rtems_event_send(e->receive_task, re); - } - - /* Check transmit interrupts */ - if (IS_FLAG_SET(is, ETH_INT_TX_UNDERRUN)) { - te = LPC24XX_ETH_EVENT_INITIALIZE; - ++e->transmit_fatal_errors; - } else if (IS_ANY_FLAG_SET(is, LPC24XX_ETH_INTERRUPT_TRANSMIT)) { - te = LPC24XX_ETH_EVENT_INTERRUPT; - ie = SET_FLAGS(ie, LPC24XX_ETH_INTERRUPT_TRANSMIT); - } - - /* Send events to transmit task */ - if (te != 0) { - ++e->transmit_interrupts; - (void) rtems_event_send(e->transmit_task, te); - } - - LPC24XX_ETH_PRINTK("interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te); - - /* Update interrupt mask */ - MAC_INTENABLE = CLEAR_FLAGS(im, ie); - - /* Clear interrupts */ - MAC_INTCLEAR = is; -} - -static void lpc24xx_eth_enable_receive_interrupts(void) -{ - rtems_interrupt_level level; - - rtems_interrupt_disable(level); - MAC_INTENABLE = SET_FLAGS(MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_RECEIVE); - rtems_interrupt_enable(level); -} - -static void lpc24xx_eth_disable_receive_interrupts(void) -{ - rtems_interrupt_level level; - - rtems_interrupt_disable(level); - MAC_INTENABLE = CLEAR_FLAGS(MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_RECEIVE); - rtems_interrupt_enable(level); -} - -static void lpc24xx_eth_enable_transmit_interrupts(void) -{ - rtems_interrupt_level level; - - rtems_interrupt_disable(level); - MAC_INTENABLE = SET_FLAGS(MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_TRANSMIT); - rtems_interrupt_enable(level); -} - -static void lpc24xx_eth_disable_transmit_interrupts(void) -{ - rtems_interrupt_level level; - - rtems_interrupt_disable(level); - MAC_INTENABLE = CLEAR_FLAGS(MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_TRANSMIT); - rtems_interrupt_enable(level); -} - -static struct mbuf *lpc24xx_eth_new_mbuf(struct ifnet *ifp, bool wait) -{ - struct mbuf *m = NULL; - int mw = wait ? M_WAIT : M_DONTWAIT; - - MGETHDR(m, mw, MT_DATA); - if (m != NULL) { - MCLGET(m, mw); - if (IS_FLAG_SET(m->m_flags, M_EXT)) { - /* Set receive interface */ - m->m_pkthdr.rcvif = ifp; - - /* Adjust by two bytes for proper IP header alignment */ - m->m_data = mtod(m, char *) + 2; - - return m; - } else { - m_free(m); - } - } - - return NULL; -} - -static bool lpc24xx_eth_add_new_mbuf( - struct ifnet *ifp, - volatile lpc24xx_eth_transfer_descriptor *desc, - struct mbuf **mbuf_table, - uint32_t i, - bool wait -) -{ - /* New mbuf */ - struct mbuf *m = lpc24xx_eth_new_mbuf(ifp, wait); - - /* Check mbuf */ - if (m != NULL) { - /* Add mbuf to queue */ - desc [i].start = mtod(m, uint32_t); - desc [i].control = SET_ETH_RX_CTRL_SIZE(0, MCLBYTES - 1) - | ETH_RX_CTRL_INTERRUPT; - - /* Add mbuf to table */ - mbuf_table [i] = m; - - return true; - } else { - return false; - } -} - -static void lpc24xx_eth_receive_task(void *arg) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - rtems_event_set events = 0; - lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg; - struct ifnet *ifp = &e->arpcom.ac_if; - volatile lpc24xx_eth_transfer_descriptor *const desc = - (volatile lpc24xx_eth_transfer_descriptor *) - LPC24XX_ETH_RECEIVE_DESC_START; - volatile lpc24xx_eth_receive_info *const info = - (volatile lpc24xx_eth_receive_info *) - LPC24XX_ETH_RECEIVE_INFO_START; - struct mbuf **const mbuf_table = - (struct mbuf **) LPC24XX_ETH_RECEIVE_MBUF_START; - uint32_t index_max = 0; - uint32_t produce_index = 0; - uint32_t consume_index = 0; - uint32_t receive_index = 0; - - LPC24XX_ETH_PRINTF("%s\n", __func__); - - /* Main event loop */ - while (true) { - bool wait_for_mbuf = false; - - /* Wait for events */ - sc = rtems_bsdnet_event_receive( - LPC24XX_ETH_EVENT_INITIALIZE | LPC24XX_ETH_EVENT_INTERRUPT, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &events - ); - RTEMS_CLEANUP_SC(sc, cleanup, "wait for events"); - - LPC24XX_ETH_PRINTF("rx: wake up: 0x%08" PRIx32 "\n", events); - - /* Initialize receiver? */ - if (IS_FLAG_SET(events, LPC24XX_ETH_EVENT_INITIALIZE)) { - /* Disable receive interrupts */ - lpc24xx_eth_disable_receive_interrupts(); - - /* Disable receiver */ - MAC_COMMAND = CLEAR_FLAG(MAC_COMMAND, ETH_CMD_RX_ENABLE); - - /* Wait for inactive status */ - while (IS_FLAG_SET(MAC_STATUS, ETH_STAT_RX_ACTIVE)) { - /* Wait */ - } - - /* Reset */ - MAC_COMMAND = SET_FLAG(MAC_COMMAND, ETH_CMD_RX_RESET); - - /* Clear receive interrupts */ - MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_RECEIVE; - - /* Index maximum (determines queue size) */ - index_max = e->receive_unit_number - 1; - - /* Move existing mbufs to the front */ - consume_index = 0; - for (produce_index = 0; produce_index <= index_max; ++produce_index) { - if (mbuf_table [produce_index] != NULL) { - mbuf_table [consume_index] = mbuf_table [produce_index]; - ++consume_index; - } - } - - /* Fill receive queue */ - for (produce_index = consume_index; produce_index <= index_max; ++produce_index) { - if ( - !lpc24xx_eth_add_new_mbuf(ifp, desc, mbuf_table, produce_index, false) - ) { - break; - } - } - - /* Check if the queue is full */ - if (produce_index == 0) { - RTEMS_DO_CLEANUP( - cleanup, - "no mbufs to fill receive queue: terminate receive task\n" - ); - } else if (produce_index <= index_max) { - /* Reduce the queue size */ - index_max = produce_index - 1; - - RTEMS_SYSLOG_ERROR("not enough mbufs to fill receive queue"); - } - - /* Receive descriptor table */ - MAC_RXDESCRIPTORNUM = index_max; - MAC_RXDESCRIPTOR = (uint32_t) desc; - MAC_RXSTATUS = (uint32_t) info; - - /* Initialize indices */ - produce_index = MAC_RXPRODUCEINDEX; - consume_index = MAC_RXCONSUMEINDEX; - receive_index = consume_index; - - /* Enable receiver */ - MAC_COMMAND = SET_FLAG(MAC_COMMAND, ETH_CMD_RX_ENABLE); - - /* Enable receive interrupts */ - lpc24xx_eth_enable_receive_interrupts(); - - /* Wait for events */ - continue; - } - - while (true) { - /* Clear receive interrupt status */ - MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_RECEIVE; - - /* Get current produce index */ - produce_index = MAC_RXPRODUCEINDEX; - - if (receive_index != produce_index) { - /* Fragment mbuf and status */ - struct mbuf *m = mbuf_table [receive_index]; - uint32_t stat = info [receive_index].status; - - /* Remove mbuf from table */ - mbuf_table [receive_index] = NULL; - - if ( - IS_FLAG_SET(stat, ETH_RX_STAT_LAST_FLAG) - && ARE_FLAGS_CLEARED(stat, LPC24XX_ETH_RX_STAT_ERRORS) - ) { - /* Ethernet header */ - struct ether_header *eh = mtod(m, struct ether_header *); - - /* Discard Ethernet header and CRC */ - int sz = (int) GET_ETH_RX_STAT_RXSIZE(stat) + 1 - - ETHER_HDR_LEN - ETHER_CRC_LEN; - - /* Update mbuf */ - m->m_len = sz; - m->m_pkthdr.len = sz; - m->m_data = mtod(m, char *) + ETHER_HDR_LEN; - - LPC24XX_ETH_PRINTF("rx: %02" PRIu32 ": %u\n", receive_index, sz); - - /* Hand over */ - ether_input(ifp, eh, m); - - /* Increment received frames counter */ - ++e->received_frames; - } else { - /* Release mbuf */ - m_free(m); - - /* Update error counters */ - if (IS_FLAG_SET(stat, ETH_RX_STAT_OVERRUN)) { - ++e->receive_overrun_errors; - } - if (IS_FLAG_CLEARED(stat, ETH_RX_STAT_LAST_FLAG)) { - ++e->receive_fragment_errors; - } - if (IS_FLAG_SET(stat, ETH_RX_STAT_CRC_ERROR)) { - ++e->receive_crc_errors; - } - if (IS_FLAG_SET(stat, ETH_RX_STAT_SYMBOL_ERROR)) { - ++e->receive_symbol_errors; - } - if (IS_FLAG_SET(stat, ETH_RX_STAT_LENGTH_ERROR)) { - ++e->receive_length_errors; - } - if (IS_FLAG_SET(stat, ETH_RX_STAT_ALIGNMENT_ERROR)) { - ++e->receive_alignment_errors; - } - if (IS_FLAG_SET(stat, ETH_RX_STAT_NO_DESCRIPTOR)) { - ++e->receive_no_descriptor_errors; - } - } - - /* Increment receive index */ - receive_index = lpc24xx_eth_increment(receive_index, index_max); - } else { - /* Nothing to do, enable receive interrupts */ - lpc24xx_eth_enable_receive_interrupts(); - break; - } - } - - /* Wait for mbuf? */ - wait_for_mbuf = - lpc24xx_eth_increment(produce_index, index_max) == consume_index; - - /* Fill queue with new mbufs */ - while (consume_index != produce_index) { - /* Add new mbuf to queue */ - if ( - !lpc24xx_eth_add_new_mbuf( - ifp, desc, mbuf_table, consume_index, wait_for_mbuf - ) - ) { - break; - } - - /* We wait for at most one mbuf */ - wait_for_mbuf = false; - - /* Increment consume index */ - consume_index = lpc24xx_eth_increment(consume_index, index_max); - - /* Update consume indices */ - MAC_RXCONSUMEINDEX = consume_index; - } - } - -cleanup: - - /* Clear task ID */ - e->receive_task = RTEMS_ID_NONE; - - /* Release network semaphore */ - rtems_bsdnet_semaphore_release(); - - /* Terminate self */ - (void) rtems_task_delete(RTEMS_SELF); -} - -static struct mbuf *lpc24xx_eth_next_fragment( - struct ifnet *ifp, - struct mbuf *m, - uint32_t *ctrl -) -{ - struct mbuf *n = NULL; - int size = 0; - - while (true) { - if (m == NULL) { - /* Dequeue first fragment of the next frame */ - IF_DEQUEUE(&ifp->if_snd, m); - - /* Empty queue? */ - if (m == NULL) { - return m; - } - } - - /* Get fragment size */ - size = m->m_len; - - if (size > 0) { - /* Now we have a not empty fragment */ - break; - } else { - /* Discard empty fragments */ - m = m_free(m); - } - } - - /* Set fragment size */ - *ctrl = SET_ETH_TX_CTRL_SIZE(0, size - 1); - - /* Discard empty successive fragments */ - n = m->m_next; - while (n != NULL && n->m_len <= 0) { - n = m_free(n); - } - m->m_next = n; - - /* Is our fragment the last in the frame? */ - if (n == NULL) { - *ctrl = SET_FLAGS(*ctrl, LPC24XX_ETH_LAST_FRAGMENT_FLAGS); - } - - return m; -} - -static void lpc24xx_eth_transmit_task(void *arg) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - rtems_event_set events = 0; - lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg; - struct ifnet *ifp = &e->arpcom.ac_if; - volatile lpc24xx_eth_transfer_descriptor *const desc = - (volatile lpc24xx_eth_transfer_descriptor *) - LPC24XX_ETH_TRANSMIT_DESC_START; - volatile uint32_t *const status = - (volatile uint32_t *) LPC24XX_ETH_TRANSMIT_STATUS_START; - volatile char *const buf = - (volatile char *) LPC24XX_ETH_TRANSMIT_BUFFER_START; - struct mbuf *m = NULL; - uint32_t index_max = e->transmit_unit_number - 1; - uint32_t produce_index = 0; - uint32_t consume_index = 0; - uint32_t ctrl = 0; - uint32_t frame_length = 0; - char *frame_buffer = NULL; - - LPC24XX_ETH_PRINTF("%s\n", __func__); - - /* Initialize descriptor table */ - for (produce_index = 0; produce_index <= index_max; ++produce_index) { - desc [produce_index].start = - (uint32_t) (buf + produce_index * LPC24XX_ETH_TRANSMIT_BUFFER_SIZE); - } - - /* Main event loop */ - while (true) { - /* Wait for events */ - sc = rtems_bsdnet_event_receive( - LPC24XX_ETH_EVENT_INITIALIZE - | LPC24XX_ETH_EVENT_START - | LPC24XX_ETH_EVENT_INTERRUPT, - RTEMS_EVENT_ANY | RTEMS_WAIT, - RTEMS_NO_TIMEOUT, - &events - ); - RTEMS_CLEANUP_SC(sc, cleanup, "wait for events"); - - LPC24XX_ETH_PRINTF("tx: wake up: 0x%08" PRIx32 "\n", events); - - /* Initialize transmitter? */ - if (IS_FLAG_SET(events, LPC24XX_ETH_EVENT_INITIALIZE)) { - /* Disable transmit interrupts */ - lpc24xx_eth_disable_transmit_interrupts(); - - /* Disable transmitter */ - MAC_COMMAND = CLEAR_FLAG(MAC_COMMAND, ETH_CMD_TX_ENABLE); - - /* Wait for inactive status */ - while (IS_FLAG_SET(MAC_STATUS, ETH_STAT_TX_ACTIVE)) { - /* Wait */ - } - - /* Reset */ - MAC_COMMAND = SET_FLAG(MAC_COMMAND, ETH_CMD_TX_RESET); - - /* Clear transmit interrupts */ - MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_TRANSMIT; - - /* Transmit descriptors */ - MAC_TXDESCRIPTORNUM = index_max; - MAC_TXDESCRIPTOR = (uint32_t) desc; - MAC_TXSTATUS = (uint32_t) status; - - /* Initialize indices */ - produce_index = MAC_TXPRODUCEINDEX; - consume_index = MAC_TXCONSUMEINDEX; - - /* Frame buffer start */ - frame_buffer = (char *) desc [produce_index].start; - - /* Enable transmitter */ - MAC_COMMAND = SET_FLAG(MAC_COMMAND, ETH_CMD_TX_ENABLE); - } - - /* Free consumed fragments */ - while (true) { - /* Save last known consume index */ - uint32_t c = consume_index; - - /* Clear transmit interrupt status */ - MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_TRANSMIT; - - /* Get new consume index */ - consume_index = MAC_TXCONSUMEINDEX; - - /* Nothing consumed in the meantime? */ - if (c == consume_index) { - break; - } - - while (c != consume_index) { - uint32_t s = status [c]; - - /* Update error counters */ - if ( - IS_ANY_FLAG_SET(s, ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR) - ) { - if (IS_FLAG_SET(s, ETH_TX_STAT_UNDERRUN)) { - ++e->transmit_underrun_errors; - } - if (IS_FLAG_SET(s, ETH_TX_STAT_LATE_COLLISION)) { - ++e->transmit_late_collision_errors; - } - if (IS_FLAG_SET(s, ETH_TX_STAT_EXCESSIVE_COLLISION)) { - ++e->transmit_excessive_collision_errors; - } - if (IS_FLAG_SET(s, ETH_TX_STAT_EXCESSIVE_DEFER)) { - ++e->transmit_excessive_defer_errors; - } - if (IS_FLAG_SET(s, ETH_TX_STAT_NO_DESCRIPTOR)) { - ++e->transmit_no_descriptor_errors; - } - } - - /* Next consume index */ - c = lpc24xx_eth_increment(c, index_max); - } - } - - /* Transmit new fragments */ - while (true) { - /* Compute next produce index */ - uint32_t p = lpc24xx_eth_increment(produce_index, index_max); - - /* Queue full? */ - if (p == consume_index) { - /* The queue is full, wait for transmit interrupt */ - break; - } - - /* Get next fragment and control value */ - m = lpc24xx_eth_next_fragment(ifp, m, &ctrl); - - /* New fragment? */ - if (m != NULL) { - size_t fragment_length = (size_t) m->m_len; - void *fragment_start = mtod(m, void *); - uint32_t new_frame_length = frame_length + fragment_length; - - /* Check buffer size */ - if (new_frame_length > LPC24XX_ETH_TRANSMIT_BUFFER_SIZE) { - LPC24XX_ETH_PRINTF("tx: overflow\n"); - - /* Discard overflow data */ - new_frame_length = LPC24XX_ETH_TRANSMIT_BUFFER_SIZE; - fragment_length = new_frame_length - frame_length; - - /* Finalize frame */ - ctrl = SET_FLAGS(ctrl, LPC24XX_ETH_LAST_FRAGMENT_FLAGS); - - /* Update error counter */ - ++e->transmit_overflow_errors; - } - - LPC24XX_ETH_PRINTF( - "tx: copy: %" PRIu32 "%s%s\n", - fragment_length, - IS_FLAG_SET(m->m_flags, M_EXT) ? ", E" : "", - IS_FLAG_SET(m->m_flags, M_PKTHDR) ? ", H" : "" - ); - - /* Copy fragment to buffer in Ethernet RAM */ - memcpy(frame_buffer, fragment_start, fragment_length); - - if (IS_FLAG_SET(ctrl, ETH_TX_CTRL_LAST)) { - /* Finalize descriptor */ - desc [produce_index].control = - SET_ETH_TX_CTRL_SIZE(ctrl, new_frame_length - 1); - - LPC24XX_ETH_PRINTF("tx: %02" PRIu32 ": %" PRIu32 "\n", produce_index, new_frame_length); - - /* Next produce index */ - produce_index = p; - - /* Update the produce index */ - MAC_TXPRODUCEINDEX = produce_index; - - /* Reinitialize frame length and buffer start */ - frame_length = 0; - frame_buffer = (char *) desc [produce_index].start; - - /* Increment transmitted frames counter */ - ++e->transmitted_frames; - } else { - /* New frame length */ - frame_length = new_frame_length; - - /* Update current frame buffer start */ - frame_buffer += fragment_length; - } - - /* Free mbuf and get next */ - m = m_free(m); - } else { - /* Nothing to transmit */ - break; - } - } - - /* No more fragments? */ - if (m == NULL) { - /* Interface is now inactive */ - ifp->if_flags = CLEAR_FLAG(ifp->if_flags, IFF_OACTIVE); - } else { - /* Enable transmit interrupts */ - lpc24xx_eth_enable_transmit_interrupts(); - } - } - -cleanup: - - /* Clear task ID */ - e->transmit_task = RTEMS_ID_NONE; - - /* Release network semaphore */ - rtems_bsdnet_semaphore_release(); - - /* Terminate self */ - (void) rtems_task_delete(RTEMS_SELF); -} - -static void lpc24xx_eth_interface_init(void *arg) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg; - struct ifnet *ifp = &e->arpcom.ac_if; - - LPC24XX_ETH_PRINTF("%s\n", __func__); - - if (e->state == LPC24XX_ETH_INITIALIZED) { - /* Enable module power */ - lpc24xx_module_enable( - LPC24XX_MODULE_ETHERNET, - LPC24XX_MODULE_PCLK_DEFAULT - ); - - /* Module IO configuration */ - #ifdef LPC24XX_ETHERNET_RMII - lpc24xx_io_config(LPC24XX_MODULE_ETHERNET, 0); - #else - lpc24xx_io_config(LPC24XX_MODULE_ETHERNET, 1); - #endif - - /* Soft reset */ - - /* Do soft reset */ - MAC_COMMAND = 0x38; - MAC_MAC1 = 0xcf00; - - /* Initialize PHY */ - /* TODO */ - - /* Reinitialize registers */ - MAC_MAC2 = 0x31; - MAC_IPGT = 0x15; - MAC_IPGR = 0x12; - MAC_CLRT = 0x370f; - MAC_MAXF = 0x0600; - MAC_SUPP = 0x0100; - MAC_TEST = 0; - #ifdef LPC24XX_ETHERNET_RMII - MAC_COMMAND = 0x0400; - #else - MAC_COMMAND = 0x0600; - #endif - MAC_INTENABLE = 0; - MAC_INTCLEAR = 0x30ff; - MAC_POWERDOWN = 0; - - /* MAC address */ - MAC_SA0 = ((uint32_t) e->arpcom.ac_enaddr [5] << 8) - | (uint32_t) e->arpcom.ac_enaddr [4]; - MAC_SA1 = ((uint32_t) e->arpcom.ac_enaddr [3] << 8) - | (uint32_t) e->arpcom.ac_enaddr [2]; - MAC_SA2 = ((uint32_t) e->arpcom.ac_enaddr [1] << 8) - | (uint32_t) e->arpcom.ac_enaddr [0]; - - /* Enable receiver */ - MAC_MAC1 = 0x03; - - /* Start receive task */ - if (e->receive_task == RTEMS_ID_NONE) { - e->receive_task = rtems_bsdnet_newproc( - "ntrx", - 4096, - lpc24xx_eth_receive_task, - e - ); - sc = rtems_event_send(e->receive_task, LPC24XX_ETH_EVENT_INITIALIZE); - RTEMS_SYSLOG_ERROR_SC(sc, "send receive initialize event"); - } - - /* Start transmit task */ - if (e->transmit_task == RTEMS_ID_NONE) { - e->transmit_task = rtems_bsdnet_newproc( - "nttx", - 4096, - lpc24xx_eth_transmit_task, - e - ); - sc = rtems_event_send(e->transmit_task, LPC24XX_ETH_EVENT_INITIALIZE); - RTEMS_SYSLOG_ERROR_SC(sc, "send transmit initialize event"); - } - - /* Change state */ - if ( - e->receive_task != RTEMS_ID_NONE && e->transmit_task != RTEMS_ID_NONE - ) { - e->state = LPC24XX_ETH_STARTED; - } - } - - if (e->state == LPC24XX_ETH_STARTED) { - /* Enable fatal interrupts */ - MAC_INTENABLE = ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN; - - /* Enable promiscous mode */ - lpc24xx_eth_enable_promiscous_mode( - IS_FLAG_SET(ifp->if_flags, IFF_PROMISC) - ); - - /* Start watchdog timer */ - ifp->if_timer = 1; - - /* Set interface to running state */ - ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_RUNNING); - - /* Change state */ - e->state = LPC24XX_ETH_RUNNING; - } -} - -static void lpc24xx_eth_interface_stats(const lpc24xx_eth_driver_entry *e) -{ - rtems_bsdnet_semaphore_release(); - - printf("received frames: %u\n", e->received_frames); - printf("receive interrupts: %u\n", e->receive_interrupts); - printf("transmitted frames: %u\n", e->transmitted_frames); - printf("transmit interrupts: %u\n", e->transmit_interrupts); - printf("receive overrun errors: %u\n", e->receive_overrun_errors); - printf("receive fragment errors: %u\n", e->receive_fragment_errors); - printf("receive CRC errors: %u\n", e->receive_crc_errors); - printf("receive symbol errors: %u\n", e->receive_symbol_errors); - printf("receive length errors: %u\n", e->receive_length_errors); - printf("receive alignment errors: %u\n", e->receive_alignment_errors); - printf("receive no descriptor errors: %u\n", e->receive_no_descriptor_errors); - printf("receive fatal errors: %u\n", e->receive_fatal_errors); - printf("transmit underrun errors: %u\n", e->transmit_underrun_errors); - printf("transmit late collision errors: %u\n", e->transmit_late_collision_errors); - printf("transmit excessive collision errors: %u\n", e->transmit_excessive_collision_errors); - printf("transmit excessive defer errors: %u\n", e->transmit_excessive_defer_errors); - printf("transmit no descriptor errors: %u\n", e->transmit_no_descriptor_errors); - printf("transmit overflow errors: %u\n", e->transmit_overflow_errors); - printf("transmit fatal errors: %u\n", e->transmit_fatal_errors); - - rtems_bsdnet_semaphore_obtain(); -} - -static int lpc24xx_eth_interface_ioctl( - struct ifnet *ifp, - ioctl_command_t command, - caddr_t data -) -{ - lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc; - int rv = 0; - - LPC24XX_ETH_PRINTF("%s\n", __func__); - - switch (command) { - case SIOCGIFMEDIA: - case SIOCSIFMEDIA: - rtems_mii_ioctl(&e->mdio_info, e, (int) command, (int *) data); - break; - case SIOCGIFADDR: - case SIOCSIFADDR: - ether_ioctl(ifp, command, data); - break; - case SIOCSIFFLAGS: - if (ifp->if_flags & IFF_RUNNING) { - /* TODO: off */ - } - if (ifp->if_flags & IFF_UP) { - ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_RUNNING); - /* TODO: init */ - } - break; - case SIO_RTEMS_SHOW_STATS: - lpc24xx_eth_interface_stats(e); - break; - default: - rv = EINVAL; - break; - } - - return rv; -} - -static void lpc24xx_eth_interface_start(struct ifnet *ifp) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc; - - ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_OACTIVE); - - sc = rtems_event_send(e->transmit_task, LPC24XX_ETH_EVENT_START); - RTEMS_SYSLOG_ERROR_SC(sc, "send transmit start event"); -} - -static void lpc24xx_eth_interface_watchdog(struct ifnet *ifp) -{ - LPC24XX_ETH_PRINTF("%s\n", __func__); -} - -static int lpc24xx_eth_attach(struct rtems_bsdnet_ifconfig *config) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - lpc24xx_eth_driver_entry *e = &lpc24xx_eth_driver_data; - struct ifnet *ifp = &e->arpcom.ac_if; - char *unit_name = NULL; - int unit_number = rtems_bsdnet_parse_driver_name(config, &unit_name); - - /* Check parameter */ - if (unit_number < 0) { - RTEMS_SYSLOG_ERROR("parse error for interface name\n"); - return 0; - } - if (unit_number != 0) { - RTEMS_DO_CLEANUP(cleanup, "unexpected unit number"); - } - if (config->hardware_address == NULL) { - RTEMS_DO_CLEANUP(cleanup, "MAC address missing"); - } - if (e->state != LPC24XX_ETH_NOT_INITIALIZED) { - RTEMS_DO_CLEANUP(cleanup, "already attached"); - } - - /* Interrupt number */ - config->irno = LPC24XX_IRQ_ETHERNET; - - /* Device control */ - config->drv_ctrl = e; - - /* Receive unit number */ - if ( - config->rbuf_count <= 0 - || config->rbuf_count > LPC24XX_ETH_RECEIVE_UNIT_NUMBER - ) { - config->rbuf_count = LPC24XX_ETH_RECEIVE_UNIT_NUMBER; - } - e->receive_unit_number = (unsigned) config->rbuf_count; - - /* Transmit unit number */ - if ( - config->xbuf_count <= 0 - || config->xbuf_count > LPC24XX_ETH_TRANSMIT_UNIT_NUMBER - ) { - config->xbuf_count = LPC24XX_ETH_TRANSMIT_UNIT_NUMBER; - } - e->transmit_unit_number = (unsigned) config->xbuf_count; - - /* Disable interrupts */ - MAC_INTENABLE = 0; - - /* Install interrupt handler */ - sc = rtems_interrupt_handler_install( - config->irno, - "Ethernet", - RTEMS_INTERRUPT_UNIQUE, - lpc24xx_eth_interrupt_handler, - e - ); - RTEMS_CLEANUP_SC(sc, cleanup, "install interrupt handler"); - - /* Copy MAC address */ - memcpy(e->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); - - /* Clear Ethernet RAM */ - memset((void *) LPC24XX_ETH_RAM_START, 0, (size_t) LPC24XX_ETH_RAM_SIZE); - - /* Set interface data */ - ifp->if_softc = e; - ifp->if_unit = (short) unit_number; - ifp->if_name = unit_name; - ifp->if_mtu = (config->mtu > 0) ? (u_long) config->mtu : ETHERMTU; - ifp->if_init = lpc24xx_eth_interface_init; - ifp->if_ioctl = lpc24xx_eth_interface_ioctl; - ifp->if_start = lpc24xx_eth_interface_start; - ifp->if_output = ether_output; - ifp->if_watchdog = lpc24xx_eth_interface_watchdog; - ifp->if_flags = config->ignore_broadcast ? 0 : IFF_BROADCAST; - ifp->if_snd.ifq_maxlen = ifqmaxlen; - ifp->if_timer = 0; - - /* Change status */ - e->state = LPC24XX_ETH_INITIALIZED; - - /* Attach the interface */ - if_attach(ifp); - ether_ifattach(ifp); - - return 1; - -cleanup: - - /* FIXME: Type */ - free(unit_name, (int) 0xdeadbeef); - - return 0; -} - -static int lpc24xx_eth_detach(struct rtems_bsdnet_ifconfig *config) -{ - /* FIXME: Detach the interface from the upper layers? */ - - /* Module soft reset */ - MAC_COMMAND = 0x38; - MAC_MAC1 = 0xcf00; - - /* FIXME: More cleanup */ - - return 0; -} - -int lpc24xx_eth_attach_detach( - struct rtems_bsdnet_ifconfig *config, - int attaching -) -{ - /* FIXME: Return value */ - - if (attaching) { - return lpc24xx_eth_attach(config); - } else { - return lpc24xx_eth_detach(config); - } -} |