summaryrefslogtreecommitdiffstats
path: root/bsps/arm/shared/net/lpc-ethernet.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/shared/net/lpc-ethernet.c')
-rw-r--r--bsps/arm/shared/net/lpc-ethernet.c1839
1 files changed, 0 insertions, 1839 deletions
diff --git a/bsps/arm/shared/net/lpc-ethernet.c b/bsps/arm/shared/net/lpc-ethernet.c
deleted file mode 100644
index ccfe1696eb..0000000000
--- a/bsps/arm/shared/net/lpc-ethernet.c
+++ /dev/null
@@ -1,1839 +0,0 @@
-/**
- * @file
- *
- * @ingroup lpc_eth
- *
- * @brief Ethernet driver.
- */
-
-/*
- * Copyright (c) 2009-2012 embedded brains GmbH. All rights reserved.
- *
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * 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.org/license/LICENSE.
- */
-
-#include <machine/rtems-bsd-kernel-space.h>
-
-#include <errno.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.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/irq.h>
-#include <bsp/lpc-ethernet-config.h>
-#include <bsp/utility.h>
-
-#if MCLBYTES > (2 * 1024)
- #error "MCLBYTES to large"
-#endif
-
-#ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
- #define LPC_ETH_CONFIG_TX_BUF_SIZE sizeof(struct mbuf *)
-#else
- #define LPC_ETH_CONFIG_TX_BUF_SIZE 1518U
-#endif
-
-#define DEFAULT_PHY 0
-#define WATCHDOG_TIMEOUT 5
-
-typedef struct {
- uint32_t start;
- uint32_t control;
-} lpc_eth_transfer_descriptor;
-
-typedef struct {
- uint32_t info;
- uint32_t hash_crc;
-} lpc_eth_receive_status;
-
-typedef struct {
- uint32_t mac1;
- uint32_t mac2;
- uint32_t ipgt;
- uint32_t ipgr;
- uint32_t clrt;
- uint32_t maxf;
- uint32_t supp;
- uint32_t test;
- uint32_t mcfg;
- uint32_t mcmd;
- uint32_t madr;
- uint32_t mwtd;
- uint32_t mrdd;
- uint32_t mind;
- uint32_t reserved_0 [2];
- uint32_t sa0;
- uint32_t sa1;
- uint32_t sa2;
- uint32_t reserved_1 [45];
- uint32_t command;
- uint32_t status;
- uint32_t rxdescriptor;
- uint32_t rxstatus;
- uint32_t rxdescriptornum;
- uint32_t rxproduceindex;
- uint32_t rxconsumeindex;
- uint32_t txdescriptor;
- uint32_t txstatus;
- uint32_t txdescriptornum;
- uint32_t txproduceindex;
- uint32_t txconsumeindex;
- uint32_t reserved_2 [10];
- uint32_t tsv0;
- uint32_t tsv1;
- uint32_t rsv;
- uint32_t reserved_3 [3];
- uint32_t flowcontrolcnt;
- uint32_t flowcontrolsts;
- uint32_t reserved_4 [34];
- uint32_t rxfilterctrl;
- uint32_t rxfilterwolsts;
- uint32_t rxfilterwolclr;
- uint32_t reserved_5 [1];
- uint32_t hashfilterl;
- uint32_t hashfilterh;
- uint32_t reserved_6 [882];
- uint32_t intstatus;
- uint32_t intenable;
- uint32_t intclear;
- uint32_t intset;
- uint32_t reserved_7 [1];
- uint32_t powerdown;
-} lpc_eth_controller;
-
-static volatile lpc_eth_controller *const lpc_eth =
- (volatile lpc_eth_controller *) LPC_ETH_CONFIG_REG_BASE;
-
-/* ETH_RX_CTRL */
-
-#define ETH_RX_CTRL_SIZE_MASK 0x000007ffU
-#define ETH_RX_CTRL_INTERRUPT 0x80000000U
-
-/* ETH_RX_STAT */
-
-#define ETH_RX_STAT_RXSIZE_MASK 0x000007ffU
-#define ETH_RX_STAT_BYTES 0x00000100U
-#define ETH_RX_STAT_CONTROL_FRAME 0x00040000U
-#define ETH_RX_STAT_VLAN 0x00080000U
-#define ETH_RX_STAT_FAIL_FILTER 0x00100000U
-#define ETH_RX_STAT_MULTICAST 0x00200000U
-#define ETH_RX_STAT_BROADCAST 0x00400000U
-#define ETH_RX_STAT_CRC_ERROR 0x00800000U
-#define ETH_RX_STAT_SYMBOL_ERROR 0x01000000U
-#define ETH_RX_STAT_LENGTH_ERROR 0x02000000U
-#define ETH_RX_STAT_RANGE_ERROR 0x04000000U
-#define ETH_RX_STAT_ALIGNMENT_ERROR 0x08000000U
-#define ETH_RX_STAT_OVERRUN 0x10000000U
-#define ETH_RX_STAT_NO_DESCRIPTOR 0x20000000U
-#define ETH_RX_STAT_LAST_FLAG 0x40000000U
-#define ETH_RX_STAT_ERROR 0x80000000U
-
-/* ETH_TX_CTRL */
-
-#define ETH_TX_CTRL_SIZE_MASK 0x7ffU
-#define ETH_TX_CTRL_SIZE_SHIFT 0
-#define ETH_TX_CTRL_OVERRIDE 0x04000000U
-#define ETH_TX_CTRL_HUGE 0x08000000U
-#define ETH_TX_CTRL_PAD 0x10000000U
-#define ETH_TX_CTRL_CRC 0x20000000U
-#define ETH_TX_CTRL_LAST 0x40000000U
-#define ETH_TX_CTRL_INTERRUPT 0x80000000U
-
-/* ETH_TX_STAT */
-
-#define ETH_TX_STAT_COLLISION_COUNT_MASK 0x01e00000U
-#define ETH_TX_STAT_DEFER 0x02000000U
-#define ETH_TX_STAT_EXCESSIVE_DEFER 0x04000000U
-#define ETH_TX_STAT_EXCESSIVE_COLLISION 0x08000000U
-#define ETH_TX_STAT_LATE_COLLISION 0x10000000U
-#define ETH_TX_STAT_UNDERRUN 0x20000000U
-#define ETH_TX_STAT_NO_DESCRIPTOR 0x40000000U
-#define ETH_TX_STAT_ERROR 0x80000000U
-
-/* ETH_INT */
-
-#define ETH_INT_RX_OVERRUN 0x00000001U
-#define ETH_INT_RX_ERROR 0x00000002U
-#define ETH_INT_RX_FINISHED 0x00000004U
-#define ETH_INT_RX_DONE 0x00000008U
-#define ETH_INT_TX_UNDERRUN 0x00000010U
-#define ETH_INT_TX_ERROR 0x00000020U
-#define ETH_INT_TX_FINISHED 0x00000040U
-#define ETH_INT_TX_DONE 0x00000080U
-#define ETH_INT_SOFT 0x00001000U
-#define ETH_INT_WAKEUP 0x00002000U
-
-/* ETH_RX_FIL_CTRL */
-
-#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST 0x00000001U
-#define ETH_RX_FIL_CTRL_ACCEPT_BROADCAST 0x00000002U
-#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST 0x00000004U
-#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST_HASH 0x00000008U
-#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST_HASH 0x00000010U
-#define ETH_RX_FIL_CTRL_ACCEPT_PERFECT 0x00000020U
-#define ETH_RX_FIL_CTRL_MAGIC_PACKET_WOL 0x00001000U
-#define ETH_RX_FIL_CTRL_RX_FILTER_WOL 0x00002000U
-
-/* ETH_CMD */
-
-#define ETH_CMD_RX_ENABLE 0x00000001U
-#define ETH_CMD_TX_ENABLE 0x00000002U
-#define ETH_CMD_REG_RESET 0x00000008U
-#define ETH_CMD_TX_RESET 0x00000010U
-#define ETH_CMD_RX_RESET 0x00000020U
-#define ETH_CMD_PASS_RUNT_FRAME 0x00000040U
-#define ETH_CMD_PASS_RX_FILTER 0X00000080U
-#define ETH_CMD_TX_FLOW_CONTROL 0x00000100U
-#define ETH_CMD_RMII 0x00000200U
-#define ETH_CMD_FULL_DUPLEX 0x00000400U
-
-/* ETH_STAT */
-
-#define ETH_STAT_RX_ACTIVE 0x00000001U
-#define ETH_STAT_TX_ACTIVE 0x00000002U
-
-/* ETH_MAC2 */
-
-#define ETH_MAC2_FULL_DUPLEX BSP_BIT32(8)
-
-/* ETH_SUPP */
-
-#define ETH_SUPP_SPEED BSP_BIT32(8)
-
-/* ETH_MCFG */
-
-#define ETH_MCFG_CLOCK_SELECT(val) BSP_FLD32(val, 2, 4)
-
-#define ETH_MCFG_RESETMIIMGMT BSP_BIT32(15)
-
-/* ETH_MCMD */
-
-#define ETH_MCMD_READ BSP_BIT32(0)
-#define ETH_MCMD_SCAN BSP_BIT32(1)
-
-/* ETH_MADR */
-
-#define ETH_MADR_REG(val) BSP_FLD32(val, 0, 4)
-#define ETH_MADR_PHY(val) BSP_FLD32(val, 8, 12)
-
-/* ETH_MIND */
-
-#define ETH_MIND_BUSY BSP_BIT32(0)
-#define ETH_MIND_SCANNING BSP_BIT32(1)
-#define ETH_MIND_NOT_VALID BSP_BIT32(2)
-#define ETH_MIND_MII_LINK_FAIL BSP_BIT32(3)
-
-/* Events */
-
-#define LPC_ETH_EVENT_INITIALIZE RTEMS_EVENT_1
-
-#define LPC_ETH_EVENT_TXSTART RTEMS_EVENT_2
-
-#define LPC_ETH_EVENT_INTERRUPT RTEMS_EVENT_3
-
-#define LPC_ETH_EVENT_STOP RTEMS_EVENT_4
-
-/* Status */
-
-#define LPC_ETH_INTERRUPT_RECEIVE \
- (ETH_INT_RX_ERROR | ETH_INT_RX_FINISHED | ETH_INT_RX_DONE)
-
-#define LPC_ETH_INTERRUPT_TRANSMIT \
- (ETH_INT_TX_DONE | ETH_INT_TX_FINISHED | ETH_INT_TX_ERROR)
-
-#define LPC_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 LPC_ETH_LAST_FRAGMENT_FLAGS \
- (ETH_TX_CTRL_OVERRIDE \
- | ETH_TX_CTRL_PAD \
- | ETH_TX_CTRL_CRC \
- | ETH_TX_CTRL_INTERRUPT \
- | ETH_TX_CTRL_LAST)
-
-/* Debug */
-
-#ifdef DEBUG
- #define LPC_ETH_PRINTF(...) printf(__VA_ARGS__)
- #define LPC_ETH_PRINTK(...) printk(__VA_ARGS__)
-#else
- #define LPC_ETH_PRINTF(...)
- #define LPC_ETH_PRINTK(...)
-#endif
-
-typedef enum {
- LPC_ETH_STATE_NOT_INITIALIZED = 0,
- LPC_ETH_STATE_DOWN,
- LPC_ETH_STATE_UP
-} lpc_eth_state;
-
-typedef struct {
- struct arpcom arpcom;
- lpc_eth_state state;
- struct rtems_mdio_info mdio;
- uint32_t anlpar;
- rtems_id receive_task;
- rtems_id transmit_task;
- unsigned rx_unit_count;
- unsigned tx_unit_count;
- volatile lpc_eth_transfer_descriptor *rx_desc_table;
- volatile lpc_eth_receive_status *rx_status_table;
- struct mbuf **rx_mbuf_table;
- volatile lpc_eth_transfer_descriptor *tx_desc_table;
- volatile uint32_t *tx_status_table;
- void *tx_buf_table;
- unsigned received_frames;
- unsigned receive_interrupts;
- unsigned transmitted_frames;
- unsigned transmit_interrupts;
- unsigned receive_drop_errors;
- 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;
- uint32_t phy_id;
- int phy;
- rtems_vector_number interrupt_number;
- rtems_id control_task;
-} lpc_eth_driver_entry;
-
-static lpc_eth_driver_entry lpc_eth_driver_data;
-
-static void lpc_eth_control_request_complete(const lpc_eth_driver_entry *e)
-{
- rtems_status_code sc = rtems_event_transient_send(e->control_task);
- assert(sc == RTEMS_SUCCESSFUL);
-}
-
-static void lpc_eth_control_request(
- lpc_eth_driver_entry *e,
- rtems_id task,
- rtems_event_set event
-)
-{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- uint32_t nest_count = 0;
-
- e->control_task = rtems_task_self();
-
- sc = rtems_bsdnet_event_send(task, event);
- assert(sc == RTEMS_SUCCESSFUL);
-
- nest_count = rtems_bsdnet_semaphore_release_recursive();
- sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
- assert(sc == RTEMS_SUCCESSFUL);
- rtems_bsdnet_semaphore_obtain_recursive(nest_count);
-
- e->control_task = 0;
-}
-
-static inline uint32_t lpc_eth_increment(
- uint32_t value,
- uint32_t cycle
-)
-{
- if (value < cycle) {
- return ++value;
- } else {
- return 0;
- }
-}
-
-static void lpc_eth_enable_promiscous_mode(bool enable)
-{
- if (enable) {
- lpc_eth->rxfilterctrl = ETH_RX_FIL_CTRL_ACCEPT_UNICAST
- | ETH_RX_FIL_CTRL_ACCEPT_MULTICAST
- | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST;
- } else {
- lpc_eth->rxfilterctrl = ETH_RX_FIL_CTRL_ACCEPT_PERFECT
- | ETH_RX_FIL_CTRL_ACCEPT_MULTICAST_HASH
- | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST;
- }
-}
-
-static void lpc_eth_interrupt_handler(void *arg)
-{
- lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg;
- rtems_event_set re = 0;
- rtems_event_set te = 0;
- uint32_t ie = 0;
-
- /* Get interrupt status */
- uint32_t im = lpc_eth->intenable;
- uint32_t is = lpc_eth->intstatus & im;
-
- /* Check receive interrupts */
- if ((is & ETH_INT_RX_OVERRUN) != 0) {
- re = LPC_ETH_EVENT_INITIALIZE;
- ++e->receive_fatal_errors;
- } else if ((is & LPC_ETH_INTERRUPT_RECEIVE) != 0) {
- re = LPC_ETH_EVENT_INTERRUPT;
- ie |= LPC_ETH_INTERRUPT_RECEIVE;
- }
-
- /* Send events to receive task */
- if (re != 0) {
- ++e->receive_interrupts;
- (void) rtems_bsdnet_event_send(e->receive_task, re);
- }
-
- /* Check transmit interrupts */
- if ((is & ETH_INT_TX_UNDERRUN) != 0) {
- te = LPC_ETH_EVENT_INITIALIZE;
- ++e->transmit_fatal_errors;
- } else if ((is & LPC_ETH_INTERRUPT_TRANSMIT) != 0) {
- te = LPC_ETH_EVENT_INTERRUPT;
- ie |= LPC_ETH_INTERRUPT_TRANSMIT;
- }
-
- /* Send events to transmit task */
- if (te != 0) {
- ++e->transmit_interrupts;
- (void) rtems_bsdnet_event_send(e->transmit_task, te);
- }
-
- LPC_ETH_PRINTK("interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te);
-
- /* Update interrupt mask */
- lpc_eth->intenable = im & ~ie;
-
- /* Clear interrupts */
- lpc_eth->intclear = is;
-}
-
-static void lpc_eth_enable_receive_interrupts(void)
-{
- rtems_interrupt_level level;
-
- rtems_interrupt_disable(level);
- lpc_eth->intenable |= LPC_ETH_INTERRUPT_RECEIVE;
- rtems_interrupt_enable(level);
-}
-
-static void lpc_eth_disable_receive_interrupts(void)
-{
- rtems_interrupt_level level;
-
- rtems_interrupt_disable(level);
- lpc_eth->intenable &= ~LPC_ETH_INTERRUPT_RECEIVE;
- rtems_interrupt_enable(level);
-}
-
-static void lpc_eth_enable_transmit_interrupts(void)
-{
- rtems_interrupt_level level;
-
- rtems_interrupt_disable(level);
- lpc_eth->intenable |= LPC_ETH_INTERRUPT_TRANSMIT;
- rtems_interrupt_enable(level);
-}
-
-static void lpc_eth_disable_transmit_interrupts(void)
-{
- rtems_interrupt_level level;
-
- rtems_interrupt_disable(level);
- lpc_eth->intenable &= ~LPC_ETH_INTERRUPT_TRANSMIT;
- rtems_interrupt_enable(level);
-}
-
-#define LPC_ETH_RX_DATA_OFFSET 2
-
-static struct mbuf *lpc_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 ((m->m_flags & M_EXT) != 0) {
- /* Set receive interface */
- m->m_pkthdr.rcvif = ifp;
-
- /* Adjust by two bytes for proper IP header alignment */
- m->m_data = mtod(m, char *) + LPC_ETH_RX_DATA_OFFSET;
-
- return m;
- } else {
- m_free(m);
- }
- }
-
- return NULL;
-}
-
-static bool lpc_eth_add_new_mbuf(
- struct ifnet *ifp,
- volatile lpc_eth_transfer_descriptor *desc,
- struct mbuf **mbufs,
- uint32_t i,
- bool wait
-)
-{
- /* New mbuf */
- struct mbuf *m = lpc_eth_new_mbuf(ifp, wait);
-
- /* Check mbuf */
- if (m != NULL) {
- /* Cache invalidate */
- rtems_cache_invalidate_multiple_data_lines(
- mtod(m, void *),
- MCLBYTES - LPC_ETH_RX_DATA_OFFSET
- );
-
- /* Add mbuf to queue */
- desc [i].start = mtod(m, uint32_t);
- desc [i].control = (MCLBYTES - LPC_ETH_RX_DATA_OFFSET - 1)
- | ETH_RX_CTRL_INTERRUPT;
-
- /* Cache flush of descriptor */
- rtems_cache_flush_multiple_data_lines(
- (void *) &desc [i],
- sizeof(desc [0])
- );
-
- /* Add mbuf to table */
- mbufs [i] = m;
-
- return true;
- } else {
- return false;
- }
-}
-
-static void lpc_eth_receive_task(void *arg)
-{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- rtems_event_set events = 0;
- lpc_eth_driver_entry *const e = (lpc_eth_driver_entry *) arg;
- struct ifnet *const ifp = &e->arpcom.ac_if;
- volatile lpc_eth_transfer_descriptor *const desc = e->rx_desc_table;
- volatile lpc_eth_receive_status *const status = e->rx_status_table;
- struct mbuf **const mbufs = e->rx_mbuf_table;
- uint32_t const index_max = e->rx_unit_count - 1;
- uint32_t produce_index = 0;
- uint32_t consume_index = 0;
-
- LPC_ETH_PRINTF("%s\n", __func__);
-
- /* Main event loop */
- while (true) {
- /* Wait for events */
- sc = rtems_bsdnet_event_receive(
- LPC_ETH_EVENT_INITIALIZE
- | LPC_ETH_EVENT_STOP
- | LPC_ETH_EVENT_INTERRUPT,
- RTEMS_EVENT_ANY | RTEMS_WAIT,
- RTEMS_NO_TIMEOUT,
- &events
- );
- assert(sc == RTEMS_SUCCESSFUL);
-
- LPC_ETH_PRINTF("rx: wake up: 0x%08" PRIx32 "\n", events);
-
- /* Stop receiver? */
- if ((events & LPC_ETH_EVENT_STOP) != 0) {
- lpc_eth_control_request_complete(e);
-
- /* Wait for events */
- continue;
- }
-
- /* Initialize receiver? */
- if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) {
- /* Disable receive interrupts */
- lpc_eth_disable_receive_interrupts();
-
- /* Disable receiver */
- lpc_eth->command &= ~ETH_CMD_RX_ENABLE;
-
- /* Wait for inactive status */
- while ((lpc_eth->status & ETH_STAT_RX_ACTIVE) != 0) {
- /* Wait */
- }
-
- /* Reset */
- lpc_eth->command |= ETH_CMD_RX_RESET;
-
- /* Clear receive interrupts */
- lpc_eth->intclear = LPC_ETH_INTERRUPT_RECEIVE;
-
- /* Move existing mbufs to the front */
- consume_index = 0;
- for (produce_index = 0; produce_index <= index_max; ++produce_index) {
- if (mbufs [produce_index] != NULL) {
- mbufs [consume_index] = mbufs [produce_index];
- ++consume_index;
- }
- }
-
- /* Fill receive queue */
- for (
- produce_index = consume_index;
- produce_index <= index_max;
- ++produce_index
- ) {
- lpc_eth_add_new_mbuf(ifp, desc, mbufs, produce_index, true);
- }
-
- /* Receive descriptor table */
- lpc_eth->rxdescriptornum = index_max;
- lpc_eth->rxdescriptor = (uint32_t) desc;
- lpc_eth->rxstatus = (uint32_t) status;
-
- /* Initialize indices */
- produce_index = lpc_eth->rxproduceindex;
- consume_index = lpc_eth->rxconsumeindex;
-
- /* Enable receiver */
- lpc_eth->command |= ETH_CMD_RX_ENABLE;
-
- /* Enable receive interrupts */
- lpc_eth_enable_receive_interrupts();
-
- lpc_eth_control_request_complete(e);
-
- /* Wait for events */
- continue;
- }
-
- while (true) {
- /* Clear receive interrupt status */
- lpc_eth->intclear = LPC_ETH_INTERRUPT_RECEIVE;
-
- /* Get current produce index */
- produce_index = lpc_eth->rxproduceindex;
-
- if (consume_index != produce_index) {
- uint32_t stat = 0;
-
- /* Fragment status */
- rtems_cache_invalidate_multiple_data_lines(
- (void *) &status [consume_index],
- sizeof(status [0])
- );
- stat = status [consume_index].info;
-
- if (
- (stat & ETH_RX_STAT_LAST_FLAG) != 0
- && (stat & LPC_ETH_RX_STAT_ERRORS) == 0
- ) {
- /* Received mbuf */
- struct mbuf *m = mbufs [consume_index];
-
- if (lpc_eth_add_new_mbuf(ifp, desc, mbufs, consume_index, false)) {
- /* Ethernet header */
- struct ether_header *eh = mtod(m, struct ether_header *);
-
- /* Discard Ethernet header and CRC */
- int sz = (int) (stat & ETH_RX_STAT_RXSIZE_MASK) + 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;
-
- LPC_ETH_PRINTF("rx: %02" PRIu32 ": %u\n", consume_index, sz);
-
- /* Hand over */
- ether_input(ifp, eh, m);
-
- /* Increment received frames counter */
- ++e->received_frames;
- } else {
- ++e->receive_drop_errors;
- }
- } else {
- /* Update error counters */
- if ((stat & ETH_RX_STAT_OVERRUN) != 0) {
- ++e->receive_overrun_errors;
- }
- if ((stat & ETH_RX_STAT_LAST_FLAG) == 0) {
- ++e->receive_fragment_errors;
- }
- if ((stat & ETH_RX_STAT_CRC_ERROR) != 0) {
- ++e->receive_crc_errors;
- }
- if ((stat & ETH_RX_STAT_SYMBOL_ERROR) != 0) {
- ++e->receive_symbol_errors;
- }
- if ((stat & ETH_RX_STAT_LENGTH_ERROR) != 0) {
- ++e->receive_length_errors;
- }
- if ((stat & ETH_RX_STAT_ALIGNMENT_ERROR) != 0) {
- ++e->receive_alignment_errors;
- }
- if ((stat & ETH_RX_STAT_NO_DESCRIPTOR) != 0) {
- ++e->receive_no_descriptor_errors;
- }
- }
-
- /* Increment and update consume index */
- consume_index = lpc_eth_increment(consume_index, index_max);
- lpc_eth->rxconsumeindex = consume_index;
- } else {
- /* Nothing to do, enable receive interrupts */
- lpc_eth_enable_receive_interrupts();
- break;
- }
- }
- }
-}
-
-static struct mbuf *lpc_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 = (uint32_t) (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 |= LPC_ETH_LAST_FRAGMENT_FLAGS;
- }
-
- return m;
-}
-
-static void lpc_eth_transmit_task(void *arg)
-{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- rtems_event_set events = 0;
- lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg;
- struct ifnet *ifp = &e->arpcom.ac_if;
- volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table;
- volatile uint32_t *const status = e->tx_status_table;
- #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
- struct mbuf **const mbufs = e->tx_buf_table;
- #else
- char *const buf = e->tx_buf_table;
- #endif
- struct mbuf *m = NULL;
- uint32_t const index_max = e->tx_unit_count - 1;
- uint32_t produce_index = 0;
- uint32_t consume_index = 0;
- uint32_t ctrl = 0;
- #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
- uint32_t frame_length = 0;
- char *frame_buffer = NULL;
- #endif
-
- LPC_ETH_PRINTF("%s\n", __func__);
-
- #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
- /* Initialize descriptor table */
- for (produce_index = 0; produce_index <= index_max; ++produce_index) {
- desc [produce_index].start =
- (uint32_t) (buf + produce_index * LPC_ETH_CONFIG_TX_BUF_SIZE);
- }
- #endif
-
- /* Main event loop */
- while (true) {
- /* Wait for events */
- sc = rtems_bsdnet_event_receive(
- LPC_ETH_EVENT_INITIALIZE
- | LPC_ETH_EVENT_STOP
- | LPC_ETH_EVENT_TXSTART
- | LPC_ETH_EVENT_INTERRUPT,
- RTEMS_EVENT_ANY | RTEMS_WAIT,
- RTEMS_NO_TIMEOUT,
- &events
- );
- assert(sc == RTEMS_SUCCESSFUL);
-
- LPC_ETH_PRINTF("tx: wake up: 0x%08" PRIx32 "\n", events);
-
- /* Stop transmitter? */
- if ((events & LPC_ETH_EVENT_STOP) != 0) {
- lpc_eth_control_request_complete(e);
-
- /* Wait for events */
- continue;
- }
-
- /* Initialize transmitter? */
- if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) {
- /* Disable transmit interrupts */
- lpc_eth_disable_transmit_interrupts();
-
- /* Disable transmitter */
- lpc_eth->command &= ~ETH_CMD_TX_ENABLE;
-
- /* Wait for inactive status */
- while ((lpc_eth->status & ETH_STAT_TX_ACTIVE) != 0) {
- /* Wait */
- }
-
- /* Reset */
- lpc_eth->command |= ETH_CMD_TX_RESET;
-
- /* Clear transmit interrupts */
- lpc_eth->intclear = LPC_ETH_INTERRUPT_TRANSMIT;
-
- /* Transmit descriptors */
- lpc_eth->txdescriptornum = index_max;
- lpc_eth->txdescriptor = (uint32_t) desc;
- lpc_eth->txstatus = (uint32_t) status;
-
- #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
- /* Discard outstanding fragments (= data loss) */
- for (produce_index = 0; produce_index <= index_max; ++produce_index) {
- struct mbuf *victim = mbufs [produce_index];
-
- if (victim != NULL) {
- m_free(victim);
- mbufs [produce_index] = NULL;
- }
- }
- #endif
-
- /* Initialize indices */
- produce_index = lpc_eth->txproduceindex;
- consume_index = lpc_eth->txconsumeindex;
-
- #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
- /* Fresh frame length and buffer start */
- frame_length = 0;
- frame_buffer = (char *) desc [produce_index].start;
- #endif
-
- /* Enable transmitter */
- lpc_eth->command |= ETH_CMD_TX_ENABLE;
-
- lpc_eth_control_request_complete(e);
- }
-
- /* Free consumed fragments */
- while (true) {
- /* Save last known consume index */
- uint32_t c = consume_index;
-
- /* Clear transmit interrupt status */
- lpc_eth->intclear = LPC_ETH_INTERRUPT_TRANSMIT;
-
- /* Get new consume index */
- consume_index = lpc_eth->txconsumeindex;
-
- /* Nothing consumed in the meantime? */
- if (c == consume_index) {
- break;
- }
-
- while (c != consume_index) {
- uint32_t s = status [c];
-
- /* Update error counters */
- if ((s & (ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR)) != 0) {
- if ((s & ETH_TX_STAT_UNDERRUN) != 0) {
- ++e->transmit_underrun_errors;
- }
- if ((s & ETH_TX_STAT_LATE_COLLISION) != 0) {
- ++e->transmit_late_collision_errors;
- }
- if ((s & ETH_TX_STAT_EXCESSIVE_COLLISION) != 0) {
- ++e->transmit_excessive_collision_errors;
- }
- if ((s & ETH_TX_STAT_EXCESSIVE_DEFER) != 0) {
- ++e->transmit_excessive_defer_errors;
- }
- if ((s & ETH_TX_STAT_NO_DESCRIPTOR) != 0) {
- ++e->transmit_no_descriptor_errors;
- }
- }
-
- #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
- /* Release mbuf */
- m_free(mbufs [c]);
- mbufs [c] = NULL;
- #endif
-
- /* Next consume index */
- c = lpc_eth_increment(c, index_max);
- }
- }
-
- /* Transmit new fragments */
- while (true) {
- /* Compute next produce index */
- uint32_t p = lpc_eth_increment(produce_index, index_max);
-
- /* Get next fragment and control value */
- m = lpc_eth_next_fragment(ifp, m, &ctrl);
-
- /* Queue full? */
- if (p == consume_index) {
- LPC_ETH_PRINTF("tx: full queue: 0x%08x\n", m);
-
- /* The queue is full, wait for transmit interrupt */
- break;
- }
-
- /* New fragment? */
- if (m != NULL) {
- #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
- /* Set the transfer data */
- rtems_cache_flush_multiple_data_lines(
- mtod(m, const void *),
- (size_t) m->m_len
- );
- desc [produce_index].start = mtod(m, uint32_t);
- desc [produce_index].control = ctrl;
- rtems_cache_flush_multiple_data_lines(
- (void *) &desc [produce_index],
- sizeof(desc [0])
- );
- mbufs [produce_index] = m;
-
- LPC_ETH_PRINTF(
- "tx: %02" PRIu32 ": %u %s\n",
- produce_index, m->m_len,
- (ctrl & ETH_TX_CTRL_LAST) != 0 ? "L" : ""
- );
-
- /* Next produce index */
- produce_index = p;
-
- /* Last fragment of a frame? */
- if ((ctrl & ETH_TX_CTRL_LAST) != 0) {
- /* Update the produce index */
- lpc_eth->txproduceindex = produce_index;
-
- /* Increment transmitted frames counter */
- ++e->transmitted_frames;
- }
-
- /* Next fragment of the frame */
- m = m->m_next;
- #else
- 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 > LPC_ETH_CONFIG_TX_BUF_SIZE) {
- LPC_ETH_PRINTF("tx: overflow\n");
-
- /* Discard overflow data */
- new_frame_length = LPC_ETH_CONFIG_TX_BUF_SIZE;
- fragment_length = new_frame_length - frame_length;
-
- /* Finalize frame */
- ctrl |= LPC_ETH_LAST_FRAGMENT_FLAGS;
-
- /* Update error counter */
- ++e->transmit_overflow_errors;
- }
-
- LPC_ETH_PRINTF(
- "tx: copy: %" PRIu32 "%s%s\n",
- fragment_length,
- (m->m_flags & M_EXT) != 0 ? ", E" : "",
- (m->m_flags & M_PKTHDR) != 0 ? ", H" : ""
- );
-
- /* Copy fragment to buffer in Ethernet RAM */
- memcpy(frame_buffer, fragment_start, fragment_length);
-
- if ((ctrl & ETH_TX_CTRL_LAST) != 0) {
- /* Finalize descriptor */
- desc [produce_index].control = (ctrl & ~ETH_TX_CTRL_SIZE_MASK)
- | (new_frame_length - 1);
-
- LPC_ETH_PRINTF(
- "tx: %02" PRIu32 ": %" PRIu32 "\n",
- produce_index,
- new_frame_length
- );
-
- /* Cache flush of data */
- rtems_cache_flush_multiple_data_lines(
- (const void *) desc [produce_index].start,
- new_frame_length
- );
-
- /* Cache flush of descriptor */
- rtems_cache_flush_multiple_data_lines(
- (void *) &desc [produce_index],
- sizeof(desc [0])
- );
-
- /* Next produce index */
- produce_index = p;
-
- /* Update the produce index */
- lpc_eth->txproduceindex = produce_index;
-
- /* Fresh 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);
- #endif
- } else {
- /* Nothing to transmit */
- break;
- }
- }
-
- /* No more fragments? */
- if (m == NULL) {
- /* Interface is now inactive */
- ifp->if_flags &= ~IFF_OACTIVE;
- } else {
- LPC_ETH_PRINTF("tx: enable interrupts\n");
-
- /* Enable transmit interrupts */
- lpc_eth_enable_transmit_interrupts();
- }
- }
-}
-
-static int lpc_eth_mdio_wait_for_not_busy(void)
-{
- rtems_interval one_second = rtems_clock_get_ticks_per_second();
- rtems_interval i = 0;
-
- while ((lpc_eth->mind & ETH_MIND_BUSY) != 0 && i < one_second) {
- rtems_task_wake_after(1);
- ++i;
- }
-
- LPC_ETH_PRINTK("tx: lpc_eth_mdio_wait %s after %d\n",
- i != one_second? "succeed": "timeout", i);
-
- return i != one_second ? 0 : ETIMEDOUT;
-}
-
-static uint32_t lpc_eth_mdio_read_anlpar(int phy)
-{
- uint32_t madr = ETH_MADR_REG(MII_ANLPAR) | ETH_MADR_PHY(phy);
- uint32_t anlpar = 0;
- int eno = 0;
-
- if (lpc_eth->madr != madr) {
- lpc_eth->madr = madr;
- }
-
- if (lpc_eth->mcmd != ETH_MCMD_READ) {
- lpc_eth->mcmd = 0;
- lpc_eth->mcmd = ETH_MCMD_READ;
- }
-
- eno = lpc_eth_mdio_wait_for_not_busy();
- if (eno == 0) {
- anlpar = lpc_eth->mrdd;
- }
-
- /* Start next read */
- lpc_eth->mcmd = 0;
- lpc_eth->mcmd = ETH_MCMD_READ;
-
- return anlpar;
-}
-
-static int lpc_eth_mdio_read(
- int phy,
- void *arg RTEMS_UNUSED,
- unsigned reg,
- uint32_t *val
-)
-{
- int eno = 0;
-
- if (0 <= phy && phy <= 31) {
- lpc_eth->madr = ETH_MADR_REG(reg) | ETH_MADR_PHY(phy);
- lpc_eth->mcmd = 0;
- lpc_eth->mcmd = ETH_MCMD_READ;
- eno = lpc_eth_mdio_wait_for_not_busy();
-
- if (eno == 0) {
- *val = lpc_eth->mrdd;
- }
- } else {
- eno = EINVAL;
- }
-
- return eno;
-}
-
-static int lpc_eth_mdio_write(
- int phy,
- void *arg RTEMS_UNUSED,
- unsigned reg,
- uint32_t val
-)
-{
- int eno = 0;
-
- if (0 <= phy && phy <= 31) {
- lpc_eth->madr = ETH_MADR_REG(reg) | ETH_MADR_PHY(phy);
- lpc_eth->mwtd = val;
- eno = lpc_eth_mdio_wait_for_not_busy();
- } else {
- eno = EINVAL;
- }
-
- return eno;
-}
-
-static int lpc_eth_phy_get_id(int phy, uint32_t *id)
-{
- uint32_t id1 = 0;
- int eno = lpc_eth_mdio_read(phy, NULL, MII_PHYIDR1, &id1);
-
- if (eno == 0) {
- uint32_t id2 = 0;
-
- eno = lpc_eth_mdio_read(phy, NULL, MII_PHYIDR2, &id2);
- if (eno == 0) {
- *id = (id1 << 16) | (id2 & 0xfff0);
- }
- }
-
- return eno;
-}
-
-#define PHY_KSZ80X1RNL 0x221550
-#define PHY_DP83848 0x20005c90
-
-typedef struct {
- unsigned reg;
- uint32_t set;
- uint32_t clear;
-} lpc_eth_phy_action;
-
-static int lpc_eth_phy_set_and_clear(
- lpc_eth_driver_entry *e,
- const lpc_eth_phy_action *actions,
- size_t n
-)
-{
- int eno = 0;
- size_t i;
-
- for (i = 0; eno == 0 && i < n; ++i) {
- const lpc_eth_phy_action *action = &actions [i];
- uint32_t val;
-
- eno = lpc_eth_mdio_read(e->phy, NULL, action->reg, &val);
- if (eno == 0) {
- val |= action->set;
- val &= ~action->clear;
- eno = lpc_eth_mdio_write(e->phy, NULL, action->reg, val);
- }
- }
-
- return eno;
-}
-
-static const lpc_eth_phy_action lpc_eth_phy_up_action_default [] = {
- { MII_BMCR, 0, BMCR_PDOWN },
- { MII_BMCR, BMCR_RESET, 0 },
- { MII_BMCR, BMCR_AUTOEN, 0 }
-};
-
-static const lpc_eth_phy_action lpc_eth_phy_up_pre_action_KSZ80X1RNL [] = {
- /* Disable slow oscillator mode */
- { 0x11, 0, 0x10 }
-};
-
-static const lpc_eth_phy_action lpc_eth_phy_up_post_action_KSZ80X1RNL [] = {
- /* Enable energy detect power down (EDPD) mode */
- { 0x18, 0x0800, 0 },
- /* Turn PLL of automatically in EDPD mode */
- { 0x10, 0x10, 0 }
-};
-
-static int lpc_eth_phy_up(lpc_eth_driver_entry *e)
-{
- int eno;
- int retries = 64;
- uint32_t val;
-
- e->phy = DEFAULT_PHY - 1;
- while (true) {
- e->phy = (e->phy + 1) % 32;
-
- --retries;
- eno = lpc_eth_phy_get_id(e->phy, &e->phy_id);
- if (
- (eno == 0 && e->phy_id != 0xfffffff0 && e->phy_id != 0)
- || retries <= 0
- ) {
- break;
- }
-
- rtems_task_wake_after(1);
- }
-
- LPC_ETH_PRINTF("lpc_eth_phy_get_id: 0x%08" PRIx32 " from phy %d retries %d\n",
- e->phy_id, e->phy, retries);
-
- if (eno == 0) {
- switch (e->phy_id) {
- case PHY_KSZ80X1RNL:
- eno = lpc_eth_phy_set_and_clear(
- e,
- &lpc_eth_phy_up_pre_action_KSZ80X1RNL [0],
- RTEMS_ARRAY_SIZE(lpc_eth_phy_up_pre_action_KSZ80X1RNL)
- );
- break;
- case PHY_DP83848:
- eno = lpc_eth_mdio_read(e->phy, NULL, 0x17, &val);
- LPC_ETH_PRINTF("phy PHY_DP83848 RBR 0x%08" PRIx32 "\n", val);
- /* val = 0x21; */
- val = 0x32 ;
- eno = lpc_eth_mdio_write(e->phy, NULL, 0x17, val);
- break;
- case 0:
- case 0xfffffff0:
- eno = EIO;
- e->phy = DEFAULT_PHY;
- break;
- default:
- break;
- }
-
- if (eno == 0) {
- eno = lpc_eth_phy_set_and_clear(
- e,
- &lpc_eth_phy_up_action_default [0],
- RTEMS_ARRAY_SIZE(lpc_eth_phy_up_action_default)
- );
- }
-
- if (eno == 0) {
- switch (e->phy_id) {
- case PHY_KSZ80X1RNL:
- eno = lpc_eth_phy_set_and_clear(
- e,
- &lpc_eth_phy_up_post_action_KSZ80X1RNL [0],
- RTEMS_ARRAY_SIZE(lpc_eth_phy_up_post_action_KSZ80X1RNL)
- );
- break;
- default:
- break;
- }
- }
- } else {
- e->phy_id = 0;
- }
-
- return eno;
-}
-
-static const lpc_eth_phy_action lpc_eth_phy_down_action_default [] = {
- { MII_BMCR, BMCR_PDOWN, 0 }
-};
-
-static const lpc_eth_phy_action lpc_eth_phy_down_post_action_KSZ80X1RNL [] = {
- /* Enable slow oscillator mode */
- { 0x11, 0x10, 0 }
-};
-
-static void lpc_eth_phy_down(lpc_eth_driver_entry *e)
-{
- int eno = lpc_eth_phy_set_and_clear(
- e,
- &lpc_eth_phy_down_action_default [0],
- RTEMS_ARRAY_SIZE(lpc_eth_phy_down_action_default)
- );
-
- if (eno == 0) {
- switch (e->phy_id) {
- case PHY_KSZ80X1RNL:
- eno = lpc_eth_phy_set_and_clear(
- e,
- &lpc_eth_phy_down_post_action_KSZ80X1RNL [0],
- RTEMS_ARRAY_SIZE(lpc_eth_phy_down_post_action_KSZ80X1RNL)
- );
- break;
- default:
- break;
- }
- }
-}
-
-static void lpc_eth_soft_reset(void)
-{
- lpc_eth->command = 0x38;
- lpc_eth->mac1 = 0xcf00;
- lpc_eth->mac1 = 0x0;
-}
-
-static int lpc_eth_up_or_down(lpc_eth_driver_entry *e, bool up)
-{
- int eno = 0;
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- struct ifnet *ifp = &e->arpcom.ac_if;
-
- if (up && e->state == LPC_ETH_STATE_DOWN) {
-
- lpc_eth_config_module_enable();
-
- /* Enable RX/TX reset and disable soft reset */
- lpc_eth->mac1 = 0xf00;
-
- /* Initialize PHY */
- /* Clock value 10 (divide by 44 ) is safe on LPC178x up to 100 MHz AHB clock */
- lpc_eth->mcfg = ETH_MCFG_CLOCK_SELECT(10) | ETH_MCFG_RESETMIIMGMT;
- rtems_task_wake_after(1);
- lpc_eth->mcfg = ETH_MCFG_CLOCK_SELECT(10);
- rtems_task_wake_after(1);
- eno = lpc_eth_phy_up(e);
-
- if (eno == 0) {
- /*
- * We must have a valid external clock from the PHY at this point,
- * otherwise the system bus hangs and only a watchdog reset helps.
- */
- lpc_eth_soft_reset();
-
- /* Reinitialize registers */
- lpc_eth->mac2 = 0x31;
- lpc_eth->ipgt = 0x15;
- lpc_eth->ipgr = 0x12;
- lpc_eth->clrt = 0x370f;
- lpc_eth->maxf = 0x0600;
- lpc_eth->supp = ETH_SUPP_SPEED;
- lpc_eth->test = 0;
- #ifdef LPC_ETH_CONFIG_RMII
- lpc_eth->command = 0x0600;
- #else
- lpc_eth->command = 0x0400;
- #endif
- lpc_eth->intenable = ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN;
- lpc_eth->intclear = 0x30ff;
- lpc_eth->powerdown = 0;
-
- /* MAC address */
- lpc_eth->sa0 = ((uint32_t) e->arpcom.ac_enaddr [5] << 8)
- | (uint32_t) e->arpcom.ac_enaddr [4];
- lpc_eth->sa1 = ((uint32_t) e->arpcom.ac_enaddr [3] << 8)
- | (uint32_t) e->arpcom.ac_enaddr [2];
- lpc_eth->sa2 = ((uint32_t) e->arpcom.ac_enaddr [1] << 8)
- | (uint32_t) e->arpcom.ac_enaddr [0];
-
- /* Enable receiver */
- lpc_eth->mac1 = 0x03;
-
- /* Initialize tasks */
- lpc_eth_control_request(e, e->receive_task, LPC_ETH_EVENT_INITIALIZE);
- lpc_eth_control_request(e, e->transmit_task, LPC_ETH_EVENT_INITIALIZE);
-
- /* Install interrupt handler */
- sc = rtems_interrupt_handler_install(
- e->interrupt_number,
- "Ethernet",
- RTEMS_INTERRUPT_UNIQUE,
- lpc_eth_interrupt_handler,
- e
- );
- assert(sc == RTEMS_SUCCESSFUL);
-
- /* Start watchdog timer */
- ifp->if_timer = 1;
-
- /* Change state */
- e->state = LPC_ETH_STATE_UP;
- }
-
- if (eno != 0) {
- ifp->if_flags &= ~IFF_UP;
- }
- } else if (!up && e->state == LPC_ETH_STATE_UP) {
- /* Remove interrupt handler */
- sc = rtems_interrupt_handler_remove(
- e->interrupt_number,
- lpc_eth_interrupt_handler,
- e
- );
- assert(sc == RTEMS_SUCCESSFUL);
-
- /* Stop tasks */
- lpc_eth_control_request(e, e->receive_task, LPC_ETH_EVENT_STOP);
- lpc_eth_control_request(e, e->transmit_task, LPC_ETH_EVENT_STOP);
-
- lpc_eth_soft_reset();
- lpc_eth_phy_down(e);
- lpc_eth_config_module_disable();
-
- /* Stop watchdog timer */
- ifp->if_timer = 0;
-
- /* Change state */
- e->state = LPC_ETH_STATE_DOWN;
- }
-
- return eno;
-}
-
-static void lpc_eth_interface_init(void *arg)
-{
- /* Nothing to do */
-}
-
-static void lpc_eth_interface_stats(lpc_eth_driver_entry *e)
-{
- int eno = EIO;
- int media = 0;
-
- if (e->state == LPC_ETH_STATE_UP) {
- media = IFM_MAKEWORD(0, 0, 0, 0);
- eno = rtems_mii_ioctl(&e->mdio, e, SIOCGIFMEDIA, &media);
- }
-
- rtems_bsdnet_semaphore_release();
-
- if (eno == 0) {
- rtems_ifmedia2str(media, NULL, 0);
- printf("\n");
- }
-
- 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 drop errors: %u\n", e->receive_drop_errors);
- 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 lpc_eth_multicast_control(
- bool add,
- struct ifreq *ifr,
- struct arpcom *ac
-)
-{
- int eno = 0;
-
- if (add) {
- eno = ether_addmulti(ifr, ac);
- } else {
- eno = ether_delmulti(ifr, ac);
- }
-
- if (eno == ENETRESET) {
- struct ether_multistep step;
- struct ether_multi *enm;
-
- eno = 0;
-
- lpc_eth->hashfilterl = 0;
- lpc_eth->hashfilterh = 0;
-
- ETHER_FIRST_MULTI(step, ac, enm);
- while (enm != NULL) {
- uint64_t addrlo = 0;
- uint64_t addrhi = 0;
-
- memcpy(&addrlo, enm->enm_addrlo, ETHER_ADDR_LEN);
- memcpy(&addrhi, enm->enm_addrhi, ETHER_ADDR_LEN);
- while (addrlo <= addrhi) {
- /* XXX: ether_crc32_le() does not work, why? */
- uint32_t crc = ether_crc32_be((uint8_t *) &addrlo, ETHER_ADDR_LEN);
- uint32_t index = (crc >> 23) & 0x3f;
-
- if (index < 32) {
- lpc_eth->hashfilterl |= 1U << index;
- } else {
- lpc_eth->hashfilterh |= 1U << (index - 32);
- }
- ++addrlo;
- }
- ETHER_NEXT_MULTI(step, enm);
- }
- }
-
- return eno;
-}
-
-static int lpc_eth_interface_ioctl(
- struct ifnet *ifp,
- ioctl_command_t cmd,
- caddr_t data
-)
-{
- lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc;
- struct ifreq *ifr = (struct ifreq *) data;
- int eno = 0;
-
- LPC_ETH_PRINTF("%s\n", __func__);
-
- switch (cmd) {
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- rtems_mii_ioctl(&e->mdio, e, cmd, &ifr->ifr_media);
- break;
- case SIOCGIFADDR:
- case SIOCSIFADDR:
- ether_ioctl(ifp, cmd, data);
- break;
- case SIOCSIFFLAGS:
- eno = lpc_eth_up_or_down(e, (ifp->if_flags & IFF_UP) != 0);
- if (eno == 0 && (ifp->if_flags & IFF_UP) != 0) {
- lpc_eth_enable_promiscous_mode((ifp->if_flags & IFF_PROMISC) != 0);
- }
- break;
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- eno = lpc_eth_multicast_control(cmd == SIOCADDMULTI, ifr, &e->arpcom);
- break;
- case SIO_RTEMS_SHOW_STATS:
- lpc_eth_interface_stats(e);
- break;
- default:
- eno = EINVAL;
- break;
- }
-
- return eno;
-}
-
-static void lpc_eth_interface_start(struct ifnet *ifp)
-{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc;
-
- ifp->if_flags |= IFF_OACTIVE;
-
- if (e->state == LPC_ETH_STATE_UP) {
- sc = rtems_bsdnet_event_send(e->transmit_task, LPC_ETH_EVENT_TXSTART);
- assert(sc == RTEMS_SUCCESSFUL);
- }
-}
-
-static void lpc_eth_interface_watchdog(struct ifnet *ifp)
-{
- lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc;
-
- if (e->state == LPC_ETH_STATE_UP) {
- uint32_t anlpar = lpc_eth_mdio_read_anlpar(e->phy);
-
- if (e->anlpar != anlpar) {
- bool full_duplex = false;
- bool speed = false;
-
- e->anlpar = anlpar;
-
- if ((anlpar & ANLPAR_TX_FD) != 0) {
- full_duplex = true;
- speed = true;
- } else if ((anlpar & ANLPAR_T4) != 0) {
- speed = true;
- } else if ((anlpar & ANLPAR_TX) != 0) {
- speed = true;
- } else if ((anlpar & ANLPAR_10_FD) != 0) {
- full_duplex = true;
- }
-
- if (full_duplex) {
- lpc_eth->mac2 |= ETH_MAC2_FULL_DUPLEX;
- } else {
- lpc_eth->mac2 &= ~ETH_MAC2_FULL_DUPLEX;
- }
-
- if (speed) {
- lpc_eth->supp |= ETH_SUPP_SPEED;
- } else {
- lpc_eth->supp &= ~ETH_SUPP_SPEED;
- }
- }
-
- ifp->if_timer = WATCHDOG_TIMEOUT;
- }
-}
-
-static unsigned lpc_eth_fixup_unit_count(int count, int default_value, int max)
-{
- if (count <= 0) {
- count = default_value;
- } else if (count > max) {
- count = max;
- }
-
- return LPC_ETH_CONFIG_UNIT_MULTIPLE
- + (((unsigned) count - 1U) & ~(LPC_ETH_CONFIG_UNIT_MULTIPLE - 1U));
-}
-
-static int lpc_eth_attach(struct rtems_bsdnet_ifconfig *config)
-{
- lpc_eth_driver_entry *e = &lpc_eth_driver_data;
- struct ifnet *ifp = &e->arpcom.ac_if;
- char *unit_name = NULL;
- int unit_index = rtems_bsdnet_parse_driver_name(config, &unit_name);
- size_t table_area_size = 0;
- char *table_area = NULL;
- char *table_location = NULL;
-
- /* Check parameter */
- if (unit_index < 0) {
- return 0;
- }
- if (unit_index != 0) {
- goto cleanup;
- }
- if (config->hardware_address == NULL) {
- goto cleanup;
- }
- if (e->state != LPC_ETH_STATE_NOT_INITIALIZED) {
- goto cleanup;
- }
-
- /* MDIO */
- e->mdio.mdio_r = lpc_eth_mdio_read;
- e->mdio.mdio_w = lpc_eth_mdio_write;
- e->mdio.has_gmii = 0;
- e->anlpar = 0;
-
- /* Interrupt number */
- config->irno = LPC_ETH_CONFIG_INTERRUPT;
-
- /* Device control */
- config->drv_ctrl = e;
-
- /* Receive unit count */
- e->rx_unit_count = lpc_eth_fixup_unit_count(
- config->rbuf_count,
- LPC_ETH_CONFIG_RX_UNIT_COUNT_DEFAULT,
- LPC_ETH_CONFIG_RX_UNIT_COUNT_MAX
- );
- config->rbuf_count = (int) e->rx_unit_count;
-
- /* Transmit unit count */
- e->tx_unit_count = lpc_eth_fixup_unit_count(
- config->xbuf_count,
- LPC_ETH_CONFIG_TX_UNIT_COUNT_DEFAULT,
- LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX
- );
- config->xbuf_count = (int) e->tx_unit_count;
-
- /* Remember interrupt number */
- e->interrupt_number = config->irno;
-
- /* Copy MAC address */
- memcpy(e->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN);
-
- /* Allocate and clear table area */
- table_area_size =
- e->rx_unit_count
- * (sizeof(lpc_eth_transfer_descriptor)
- + sizeof(lpc_eth_receive_status)
- + sizeof(struct mbuf *))
- + e->tx_unit_count
- * (sizeof(lpc_eth_transfer_descriptor)
- + sizeof(uint32_t)
- + LPC_ETH_CONFIG_TX_BUF_SIZE);
- table_area = lpc_eth_config_alloc_table_area(table_area_size);
- if (table_area == NULL) {
- goto cleanup;
- }
- memset(table_area, 0, table_area_size);
-
- table_location = table_area;
-
- /*
- * The receive status table must be the first one since it has the strictest
- * alignment requirements.
- */
- e->rx_status_table = (volatile lpc_eth_receive_status *) table_location;
- table_location += e->rx_unit_count * sizeof(e->rx_status_table [0]);
-
- e->rx_desc_table = (volatile lpc_eth_transfer_descriptor *) table_location;
- table_location += e->rx_unit_count * sizeof(e->rx_desc_table [0]);
-
- e->rx_mbuf_table = (struct mbuf **) table_location;
- table_location += e->rx_unit_count * sizeof(e->rx_mbuf_table [0]);
-
- e->tx_desc_table = (volatile lpc_eth_transfer_descriptor *) table_location;
- table_location += e->tx_unit_count * sizeof(e->tx_desc_table [0]);
-
- e->tx_status_table = (volatile uint32_t *) table_location;
- table_location += e->tx_unit_count * sizeof(e->tx_status_table [0]);
-
- e->tx_buf_table = table_location;
-
- /* Set interface data */
- ifp->if_softc = e;
- ifp->if_unit = (short) unit_index;
- ifp->if_name = unit_name;
- ifp->if_mtu = (config->mtu > 0) ? (u_long) config->mtu : ETHERMTU;
- ifp->if_init = lpc_eth_interface_init;
- ifp->if_ioctl = lpc_eth_interface_ioctl;
- ifp->if_start = lpc_eth_interface_start;
- ifp->if_output = ether_output;
- ifp->if_watchdog = lpc_eth_interface_watchdog;
- ifp->if_flags = IFF_MULTICAST | IFF_BROADCAST | IFF_SIMPLEX;
- ifp->if_snd.ifq_maxlen = ifqmaxlen;
- ifp->if_timer = 0;
-
- /* Create tasks */
- e->receive_task = rtems_bsdnet_newproc(
- "ntrx",
- 4096,
- lpc_eth_receive_task,
- e
- );
- e->transmit_task = rtems_bsdnet_newproc(
- "nttx",
- 4096,
- lpc_eth_transmit_task,
- e
- );
-
- /* Change status */
- ifp->if_flags |= IFF_RUNNING;
- e->state = LPC_ETH_STATE_DOWN;
-
- /* Attach the interface */
- if_attach(ifp);
- ether_ifattach(ifp);
-
- return 1;
-
-cleanup:
-
- lpc_eth_config_free_table_area(table_area);
-
- /* FIXME: Type */
- free(unit_name, (int) 0xdeadbeef);
-
- return 0;
-}
-
-static int lpc_eth_detach(
- struct rtems_bsdnet_ifconfig *config RTEMS_UNUSED
-)
-{
- /* FIXME: Detach the interface from the upper layers? */
-
- /* Module soft reset */
- lpc_eth->command = 0x38;
- lpc_eth->mac1 = 0xcf00;
-
- /* FIXME: More cleanup */
-
- return 0;
-}
-
-int lpc_eth_attach_detach(
- struct rtems_bsdnet_ifconfig *config,
- int attaching
-)
-{
- /* FIXME: Return value */
-
- if (attaching) {
- return lpc_eth_attach(config);
- } else {
- return lpc_eth_detach(config);
- }
-}