if_lpe.c: Use interface transmit

This avoids the need for a transmit task and transmit interrupts.
This commit is contained in:
Sebastian Huber
2022-06-22 15:39:15 +02:00
parent 8b085f2fcd
commit b7787bd311

View File

@@ -7,13 +7,7 @@
*/ */
/* /*
* Copyright (c) 2009-2012 embedded brains GmbH. All rights reserved. * Copyright (C) 2009, 2022 embedded brains GmbH
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
* *
* The license and distribution terms for this file may be * The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at * found in the file LICENSE in this distribution or at
@@ -264,8 +258,6 @@ static volatile lpc_eth_controller *const lpc_eth =
#define LPC_ETH_EVENT_INIT_TX RTEMS_EVENT_1 #define LPC_ETH_EVENT_INIT_TX RTEMS_EVENT_1
#define LPC_ETH_EVENT_TXSTART RTEMS_EVENT_2
#define LPC_ETH_EVENT_INTERRUPT RTEMS_EVENT_3 #define LPC_ETH_EVENT_INTERRUPT RTEMS_EVENT_3
#define LPC_ETH_EVENT_STOP RTEMS_EVENT_4 #define LPC_ETH_EVENT_STOP RTEMS_EVENT_4
@@ -275,9 +267,6 @@ static volatile lpc_eth_controller *const lpc_eth =
#define LPC_ETH_INTERRUPT_RECEIVE \ #define LPC_ETH_INTERRUPT_RECEIVE \
(ETH_INT_RX_ERROR | ETH_INT_RX_FINISHED | ETH_INT_RX_DONE) (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 \ #define LPC_ETH_RX_STAT_ERRORS \
(ETH_RX_STAT_CRC_ERROR \ (ETH_RX_STAT_CRC_ERROR \
| ETH_RX_STAT_SYMBOL_ERROR \ | ETH_RX_STAT_SYMBOL_ERROR \
@@ -317,7 +306,6 @@ typedef struct {
uint32_t anlpar; uint32_t anlpar;
struct callout watchdog_callout; struct callout watchdog_callout;
rtems_id receive_task; rtems_id receive_task;
rtems_id transmit_task;
unsigned rx_unit_count; unsigned rx_unit_count;
unsigned tx_unit_count; unsigned tx_unit_count;
volatile lpc_eth_transfer_descriptor *rx_desc_table; volatile lpc_eth_transfer_descriptor *rx_desc_table;
@@ -331,7 +319,6 @@ typedef struct {
unsigned received_frames; unsigned received_frames;
unsigned receive_interrupts; unsigned receive_interrupts;
unsigned transmitted_frames; unsigned transmitted_frames;
unsigned transmit_interrupts;
unsigned receive_drop_errors; unsigned receive_drop_errors;
unsigned receive_overrun_errors; unsigned receive_overrun_errors;
unsigned receive_fragment_errors; unsigned receive_fragment_errors;
@@ -435,26 +422,14 @@ static void lpc_eth_interrupt_handler(void *arg)
} else if ((is & LPC_ETH_INTERRUPT_RECEIVE) != 0) { } else if ((is & LPC_ETH_INTERRUPT_RECEIVE) != 0) {
re = LPC_ETH_EVENT_INTERRUPT; re = LPC_ETH_EVENT_INTERRUPT;
ie |= LPC_ETH_INTERRUPT_RECEIVE; ie |= LPC_ETH_INTERRUPT_RECEIVE;
++e->receive_interrupts;
} }
/* Send events to receive task */ /* Send events to receive task */
if (re != 0) { if (re != 0) {
++e->receive_interrupts;
(void) rtems_event_send(e->receive_task, re); (void) rtems_event_send(e->receive_task, re);
} }
/* Check transmit interrupts */
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_event_send(e->transmit_task, te);
}
LPC_ETH_PRINTK("interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te); LPC_ETH_PRINTK("interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te);
/* Update interrupt mask */ /* Update interrupt mask */
@@ -482,24 +457,6 @@ static void lpc_eth_disable_receive_interrupts(void)
rtems_interrupt_enable(level); 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);
}
static void lpc_eth_initialize_transmit(lpc_eth_driver_entry *e) static void lpc_eth_initialize_transmit(lpc_eth_driver_entry *e)
{ {
volatile uint32_t *const status = e->tx_status_table; volatile uint32_t *const status = e->tx_status_table;
@@ -512,9 +469,6 @@ static void lpc_eth_initialize_transmit(lpc_eth_driver_entry *e)
#endif #endif
uint32_t produce_index; uint32_t produce_index;
/* Disable transmit interrupts */
lpc_eth_disable_transmit_interrupts();
/* Disable transmitter */ /* Disable transmitter */
lpc_eth->command &= ~ETH_CMD_TX_ENABLE; lpc_eth->command &= ~ETH_CMD_TX_ENABLE;
@@ -526,9 +480,6 @@ static void lpc_eth_initialize_transmit(lpc_eth_driver_entry *e)
/* Reset */ /* Reset */
lpc_eth->command |= ETH_CMD_TX_RESET; lpc_eth->command |= ETH_CMD_TX_RESET;
/* Clear transmit interrupts */
lpc_eth->intclear = LPC_ETH_INTERRUPT_TRANSMIT;
/* Transmit descriptors */ /* Transmit descriptors */
lpc_eth->txdescriptornum = index_max; lpc_eth->txdescriptornum = index_max;
lpc_eth->txdescriptor = (uint32_t) desc; lpc_eth->txdescriptor = (uint32_t) desc;
@@ -537,12 +488,8 @@ static void lpc_eth_initialize_transmit(lpc_eth_driver_entry *e)
#ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
/* Discard outstanding fragments (= data loss) */ /* Discard outstanding fragments (= data loss) */
for (produce_index = 0; produce_index <= index_max; ++produce_index) { for (produce_index = 0; produce_index <= index_max; ++produce_index) {
struct mbuf *victim = mbufs [produce_index]; m_freem(mbufs [produce_index]);
mbufs [produce_index] = NULL;
if (victim != NULL) {
m_free(victim);
mbufs [produce_index] = NULL;
}
} }
#else #else
/* Initialize descriptor table */ /* Initialize descriptor table */
@@ -815,20 +762,10 @@ static struct mbuf *lpc_eth_next_fragment(
uint32_t *ctrl uint32_t *ctrl
) )
{ {
struct mbuf *n = NULL; struct mbuf *n;
int size = 0; int size;
while (true) { 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 */ /* Get fragment size */
size = m->m_len; size = m->m_len;
@@ -836,8 +773,12 @@ static struct mbuf *lpc_eth_next_fragment(
/* Now we have a not empty fragment */ /* Now we have a not empty fragment */
break; break;
} else { } else {
/* Discard empty fragments */ /* Skip empty fragments */
m = m_free(m); m = m->m_next;
if (m == NULL) {
return NULL;
}
} }
} }
@@ -859,266 +800,224 @@ static struct mbuf *lpc_eth_next_fragment(
return m; return m;
} }
static void lpc_eth_transmit_task(rtems_task_argument arg) static void lpc_eth_tx_reclaim(lpc_eth_driver_entry *e, struct ifnet *ifp)
{ {
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->ifp;
volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table;
volatile uint32_t *const status = e->tx_status_table; volatile uint32_t *const status = e->tx_status_table;
volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table;
#ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
struct mbuf **const mbufs = e->tx_buf_table; struct mbuf **const mbufs = e->tx_buf_table;
#else #else
char *const buf = e->tx_buf_table; char *const buf = e->tx_buf_table;
#endif #endif
struct mbuf *m = NULL;
uint32_t const index_max = e->tx_unit_count - 1; uint32_t const index_max = e->tx_unit_count - 1;
uint32_t ctrl = 0; uint32_t consume_index = e->tx_consume_index;
LPC_ETH_PRINTF("%s\n", __func__); /* Free consumed fragments */
/* Main event loop */
while (true) { while (true) {
uint32_t produce_index; /* Save last known consume index */
uint32_t consume_index; uint32_t c = consume_index;
#ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
uint32_t frame_length;
char *frame_buffer;
#endif
/* Wait for events */ /* Get new consume index */
sc = rtems_event_receive( consume_index = lpc_eth->txconsumeindex;
LPC_ETH_EVENT_STOP
| LPC_ETH_EVENT_TXSTART
| LPC_ETH_EVENT_INTERRUPT,
RTEMS_EVENT_ANY | RTEMS_WAIT,
RTEMS_NO_TIMEOUT,
&events
);
BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
LPC_ETH_PRINTF("tx: wake up: 0x%08" PRIx32 "\n", events); /* Nothing consumed in the meantime? */
if (c == consume_index) {
/* Stop transmitter? */ break;
if ((events & LPC_ETH_EVENT_STOP) != 0) {
lpc_eth_control_request_complete(e);
/* Wait for events */
continue;
} }
LPE_LOCK(e); while (c != consume_index) {
uint32_t s = status [c];
/* Get indices */ /* Update error counters */
produce_index = e->tx_produce_index; if ((s & (ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR)) != 0) {
consume_index = e->tx_consume_index; if ((s & ETH_TX_STAT_UNDERRUN) != 0) {
++e->transmit_underrun_errors;
#ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA }
/* Fresh frame length and buffer start */ if ((s & ETH_TX_STAT_LATE_COLLISION) != 0) {
frame_length = 0; ++e->transmit_late_collision_errors;
frame_buffer = (char *) desc [produce_index].start; }
#endif if ((s & ETH_TX_STAT_EXCESSIVE_COLLISION) != 0) {
++e->transmit_excessive_collision_errors;
/* Free consumed fragments */ }
while (true) { if ((s & ETH_TX_STAT_EXCESSIVE_DEFER) != 0) {
/* Save last known consume index */ ++e->transmit_excessive_defer_errors;
uint32_t c = consume_index; }
if ((s & ETH_TX_STAT_NO_DESCRIPTOR) != 0) {
/* Clear transmit interrupt status */ ++e->transmit_no_descriptor_errors;
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) { #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
uint32_t s = status [c]; /* Release mbuf */
m_freem(mbufs [c]);
mbufs [c] = NULL;
#endif
/* Update error counters */ /* Next consume index */
if ((s & (ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR)) != 0) { c = lpc_eth_increment(c, index_max);
if ((s & ETH_TX_STAT_UNDERRUN) != 0) { }
++e->transmit_underrun_errors; }
}
if ((s & ETH_TX_STAT_LATE_COLLISION) != 0) { e->tx_consume_index = consume_index;
++e->transmit_late_collision_errors; }
}
if ((s & ETH_TX_STAT_EXCESSIVE_COLLISION) != 0) { static int lpc_eth_tx_enqueue(
++e->transmit_excessive_collision_errors; lpc_eth_driver_entry *e,
} struct ifnet *ifp,
if ((s & ETH_TX_STAT_EXCESSIVE_DEFER) != 0) { struct mbuf *m0
++e->transmit_excessive_defer_errors; )
} {
if ((s & ETH_TX_STAT_NO_DESCRIPTOR) != 0) { volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table;
++e->transmit_no_descriptor_errors; #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
} struct mbuf **const mbufs = e->tx_buf_table;
#else
char *const buf = e->tx_buf_table;
uint32_t frame_length;
char *frame_buffer;
#endif
uint32_t const index_max = e->tx_unit_count - 1;
uint32_t produce_index = e->tx_produce_index;
uint32_t consume_index = e->tx_consume_index;
struct mbuf *m = m0;
while (true) {
uint32_t ctrl;
/* Compute next produce index */
uint32_t p = lpc_eth_increment(produce_index, index_max);
/* Queue full? */
if (p == consume_index) {
LPC_ETH_PRINTF("tx: full queue: 0x%08x\n", m);
/* The queue is full */
return ENOBUFS;
}
/* Get next fragment and control value */
m = lpc_eth_next_fragment(ifp, m, &ctrl);
/* 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])
);
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;
e->tx_produce_index = produce_index;
mbufs [produce_index] = m0;
/* Increment transmitted frames counter */
++e->transmitted_frames;
return 0;
} }
#ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA /* Next fragment of the frame */
/* Release mbuf */ m = m->m_next;
m_free(mbufs [c]); #else
mbufs [c] = NULL; size_t fragment_length = (size_t) m->m_len;
#endif void *fragment_start = mtod(m, void *);
uint32_t new_frame_length = frame_length + fragment_length;
/* Next consume index */ /* Check buffer size */
c = lpc_eth_increment(c, index_max); if (new_frame_length > LPC_ETH_CONFIG_TX_BUF_SIZE) {
} LPC_ETH_PRINTF("tx: overflow\n");
}
/* Transmit new fragments */ /* Discard overflow data */
while (true) { new_frame_length = LPC_ETH_CONFIG_TX_BUF_SIZE;
/* Compute next produce index */ fragment_length = new_frame_length - frame_length;
uint32_t p = lpc_eth_increment(produce_index, index_max);
/* Get next fragment and control value */ /* Finalize frame */
m = lpc_eth_next_fragment(ifp, m, &ctrl); ctrl |= LPC_ETH_LAST_FRAGMENT_FLAGS;
/* Queue full? */ /* Update error counter */
if (p == consume_index) { ++e->transmit_overflow_errors;
LPC_ETH_PRINTF("tx: full queue: 0x%08x\n", m); }
/* The queue is full, wait for transmit interrupt */ LPC_ETH_PRINTF(
break; "tx: copy: %" PRIu32 "%s%s\n",
} fragment_length,
(m->m_flags & M_EXT) != 0 ? ", E" : "",
(m->m_flags & M_PKTHDR) != 0 ? ", H" : ""
);
/* New fragment? */ /* Copy fragment to buffer in Ethernet RAM */
if (m != NULL) { memcpy(frame_buffer, fragment_start, fragment_length);
#ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
/* Set the transfer data */ if ((ctrl & ETH_TX_CTRL_LAST) != 0) {
rtems_cache_flush_multiple_data_lines( /* Finalize descriptor */
mtod(m, const void *), desc [produce_index].control = (ctrl & ~ETH_TX_CTRL_SIZE_MASK)
(size_t) m->m_len | (new_frame_length - 1);
LPC_ETH_PRINTF(
"tx: %02" PRIu32 ": %" PRIu32 "\n",
produce_index,
new_frame_length
); );
desc [produce_index].start = mtod(m, uint32_t);
desc [produce_index].control = ctrl; /* 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( rtems_cache_flush_multiple_data_lines(
(void *) &desc [produce_index], (void *) &desc [produce_index],
sizeof(desc [0]) 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 */ /* Next produce index */
produce_index = p; produce_index = p;
/* Last fragment of a frame? */ /* Update the produce index */
if ((ctrl & ETH_TX_CTRL_LAST) != 0) { lpc_eth->txproduceindex = produce_index;
/* Update the produce index */
lpc_eth->txproduceindex = produce_index;
/* Increment transmitted frames counter */ /* Fresh frame length and buffer start */
++e->transmitted_frames; frame_length = 0;
} frame_buffer = (char *) desc [produce_index].start;
/* Next fragment of the frame */ /* Increment transmitted frames counter */
m = m->m_next; ++e->transmitted_frames;
#else } else {
size_t fragment_length = (size_t) m->m_len; /* New frame length */
void *fragment_start = mtod(m, void *); frame_length = new_frame_length;
uint32_t new_frame_length = frame_length + fragment_length;
/* Check buffer size */ /* Update current frame buffer start */
if (new_frame_length > LPC_ETH_CONFIG_TX_BUF_SIZE) { frame_buffer += fragment_length;
LPC_ETH_PRINTF("tx: overflow\n"); }
/* Discard overflow data */ /* Free mbuf and get next */
new_frame_length = LPC_ETH_CONFIG_TX_BUF_SIZE; m = m_free(m);
fragment_length = new_frame_length - frame_length; #endif
/* 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;
}
}
/* Save indices */
e->tx_produce_index = produce_index;
e->tx_consume_index = consume_index;
/* No more fragments? */
if (m == NULL) {
/* Interface is now inactive */
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
} else { } else {
LPC_ETH_PRINTF("tx: enable interrupts\n"); /* Nothing to transmit */
m_freem(m0);
/* Enable transmit interrupts */ return 0;
lpc_eth_enable_transmit_interrupts();
} }
LPE_UNLOCK(e);
} }
} }
@@ -1484,9 +1383,8 @@ static int lpc_eth_up_or_down(lpc_eth_driver_entry *e, bool up)
); );
BSD_ASSERT(sc == RTEMS_SUCCESSFUL); BSD_ASSERT(sc == RTEMS_SUCCESSFUL);
/* Stop tasks */ /* Stop task */
lpc_eth_control_request(e, e->receive_task, LPC_ETH_EVENT_STOP); 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_soft_reset();
lpc_eth_phy_down(e); lpc_eth_phy_down(e);
@@ -1604,17 +1502,38 @@ static int lpc_eth_interface_ioctl(
return eno; return eno;
} }
static void lpc_eth_interface_start(struct ifnet *ifp) static int lpc_eth_interface_transmit(struct ifnet *ifp, struct mbuf *m)
{ {
rtems_status_code sc = RTEMS_SUCCESSFUL;
lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc; lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc;
int eno;
ifp->if_drv_flags |= IFF_DRV_OACTIVE; LPE_LOCK(e);
if (e->state == LPC_ETH_STATE_UP) { if (e->state == LPC_ETH_STATE_UP) {
sc = rtems_event_send(e->transmit_task, LPC_ETH_EVENT_TXSTART); eno = lpc_eth_tx_enqueue(e, ifp, m);
BSD_ASSERT(sc == RTEMS_SUCCESSFUL); lpc_eth_tx_reclaim(e, ifp);
if (__predict_false(eno != 0)) {
struct mbuf *n;
n = m_defrag(m, M_NOWAIT);
if (n != NULL) {
m = n;
}
eno = lpc_eth_tx_enqueue(e, ifp, m);
}
} else {
eno = ENETDOWN;
} }
if (eno != 0) {
m_freem(m);
if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
}
LPE_UNLOCK(e);
return eno;
} }
static void lpc_eth_interface_watchdog(void *arg) static void lpc_eth_interface_watchdog(void *arg)
@@ -1772,7 +1691,7 @@ static int lpc_eth_attach(device_t dev)
if_initname(ifp, device_get_name(dev), device_get_unit(dev)); if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_init = lpc_eth_interface_init; ifp->if_init = lpc_eth_interface_init;
ifp->if_ioctl = lpc_eth_interface_ioctl; ifp->if_ioctl = lpc_eth_interface_ioctl;
ifp->if_start = lpc_eth_interface_start; ifp->if_transmit = lpc_eth_interface_transmit;
ifp->if_qflush = if_qflush; ifp->if_qflush = if_qflush;
ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
IFQ_SET_MAXLEN(&ifp->if_snd, LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX - 1); IFQ_SET_MAXLEN(&ifp->if_snd, LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX - 1);
@@ -1798,21 +1717,6 @@ static int lpc_eth_attach(device_t dev)
(rtems_task_argument)e (rtems_task_argument)e
); );
BSD_ASSERT(status == RTEMS_SUCCESSFUL); BSD_ASSERT(status == RTEMS_SUCCESSFUL);
status = rtems_task_create(
rtems_build_name('n', 't', 't', 'x'),
rtems_bsd_get_task_priority(device_get_name(e->dev)),
4096,
RTEMS_DEFAULT_MODES,
RTEMS_DEFAULT_ATTRIBUTES,
&e->transmit_task
);
BSD_ASSERT(status == RTEMS_SUCCESSFUL);
status = rtems_task_start(
e->transmit_task,
lpc_eth_transmit_task,
(rtems_task_argument)e
);
BSD_ASSERT(status == RTEMS_SUCCESSFUL);
if_link_state_change(e->ifp, LINK_STATE_UP); if_link_state_change(e->ifp, LINK_STATE_UP);