if_lpe.c: Move transmit initialization

Move the transmit initialization out of the transmit task to be able to
remove the transmit task in the next patch.
This commit is contained in:
Sebastian Huber 2022-06-22 14:41:38 +02:00
parent ff4c60af7a
commit 1056349b4e

View File

@ -260,7 +260,9 @@ static volatile lpc_eth_controller *const lpc_eth =
/* Events */ /* Events */
#define LPC_ETH_EVENT_INITIALIZE RTEMS_EVENT_1 #define LPC_ETH_EVENT_INIT_RX RTEMS_EVENT_0
#define LPC_ETH_EVENT_INIT_TX RTEMS_EVENT_1
#define LPC_ETH_EVENT_TXSTART RTEMS_EVENT_2 #define LPC_ETH_EVENT_TXSTART RTEMS_EVENT_2
@ -324,6 +326,8 @@ typedef struct {
volatile lpc_eth_transfer_descriptor *tx_desc_table; volatile lpc_eth_transfer_descriptor *tx_desc_table;
volatile uint32_t *tx_status_table; volatile uint32_t *tx_status_table;
void *tx_buf_table; void *tx_buf_table;
uint32_t tx_produce_index;
uint32_t tx_consume_index;
unsigned received_frames; unsigned received_frames;
unsigned receive_interrupts; unsigned receive_interrupts;
unsigned transmitted_frames; unsigned transmitted_frames;
@ -418,9 +422,16 @@ static void lpc_eth_interrupt_handler(void *arg)
uint32_t is = lpc_eth->intstatus & im; uint32_t is = lpc_eth->intstatus & im;
/* Check receive interrupts */ /* Check receive interrupts */
if ((is & ETH_INT_RX_OVERRUN) != 0) { if ((is & (ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN)) != 0) {
re = LPC_ETH_EVENT_INITIALIZE; if ((is & ETH_INT_RX_OVERRUN) != 0) {
++e->receive_fatal_errors; re = LPC_ETH_EVENT_INIT_RX;
++e->receive_fatal_errors;
}
if ((is & ETH_INT_TX_UNDERRUN) != 0) {
re = LPC_ETH_EVENT_INIT_TX;
++e->transmit_fatal_errors;
}
} 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;
@ -433,10 +444,7 @@ static void lpc_eth_interrupt_handler(void *arg)
} }
/* Check transmit interrupts */ /* Check transmit interrupts */
if ((is & ETH_INT_TX_UNDERRUN) != 0) { if ((is & LPC_ETH_INTERRUPT_TRANSMIT) != 0) {
te = LPC_ETH_EVENT_INITIALIZE;
++e->transmit_fatal_errors;
} else if ((is & LPC_ETH_INTERRUPT_TRANSMIT) != 0) {
te = LPC_ETH_EVENT_INTERRUPT; te = LPC_ETH_EVENT_INTERRUPT;
ie |= LPC_ETH_INTERRUPT_TRANSMIT; ie |= LPC_ETH_INTERRUPT_TRANSMIT;
} }
@ -492,6 +500,66 @@ static void lpc_eth_disable_transmit_interrupts(void)
rtems_interrupt_enable(level); rtems_interrupt_enable(level);
} }
static void lpc_eth_initialize_transmit(lpc_eth_driver_entry *e)
{
volatile uint32_t *const status = e->tx_status_table;
uint32_t const index_max = e->tx_unit_count - 1;
volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_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
uint32_t produce_index;
/* 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;
}
}
#else
/* 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
/* Initialize indices */
e->tx_produce_index = lpc_eth->txproduceindex;
e->tx_consume_index = lpc_eth->txconsumeindex;
/* Enable transmitter */
lpc_eth->command |= ETH_CMD_TX_ENABLE;
}
#define LPC_ETH_RX_DATA_OFFSET 2 #define LPC_ETH_RX_DATA_OFFSET 2
static struct mbuf *lpc_eth_new_mbuf(struct ifnet *ifp, bool wait) static struct mbuf *lpc_eth_new_mbuf(struct ifnet *ifp, bool wait)
@ -576,7 +644,8 @@ static void lpc_eth_receive_task(rtems_task_argument arg)
while (true) { while (true) {
/* Wait for events */ /* Wait for events */
sc = rtems_event_receive( sc = rtems_event_receive(
LPC_ETH_EVENT_INITIALIZE LPC_ETH_EVENT_INIT_RX
| LPC_ETH_EVENT_INIT_TX
| LPC_ETH_EVENT_STOP | LPC_ETH_EVENT_STOP
| LPC_ETH_EVENT_INTERRUPT, | LPC_ETH_EVENT_INTERRUPT,
RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_EVENT_ANY | RTEMS_WAIT,
@ -595,60 +664,68 @@ static void lpc_eth_receive_task(rtems_task_argument arg)
continue; continue;
} }
/* Initialize receiver? */ /* Initialize receiver or transmitter? */
if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) { if ((events & (LPC_ETH_EVENT_INIT_RX | LPC_ETH_EVENT_INIT_TX)) != 0) {
/* Disable receive interrupts */ if ((events & LPC_ETH_EVENT_INIT_RX) != 0) {
lpc_eth_disable_receive_interrupts(); /* Disable receive interrupts */
lpc_eth_disable_receive_interrupts();
/* Disable receiver */ /* Disable receiver */
lpc_eth->command &= ~ETH_CMD_RX_ENABLE; lpc_eth->command &= ~ETH_CMD_RX_ENABLE;
/* Wait for inactive status */ /* Wait for inactive status */
while ((lpc_eth->status & ETH_STAT_RX_ACTIVE) != 0) { while ((lpc_eth->status & ETH_STAT_RX_ACTIVE) != 0) {
/* Wait */ /* 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;
} }
/* 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);
} }
/* Fill receive queue */ if ((events & LPC_ETH_EVENT_INIT_TX) != 0) {
for ( LPE_LOCK(e);
produce_index = consume_index; lpc_eth_initialize_transmit(e);
produce_index <= index_max; LPE_UNLOCK(e);
++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 */ /* Wait for events */
continue; continue;
} }
@ -797,30 +874,22 @@ static void lpc_eth_transmit_task(rtems_task_argument arg)
#endif #endif
struct mbuf *m = NULL; 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 produce_index = 0;
uint32_t consume_index = 0;
uint32_t ctrl = 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__); 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 */ /* Main event loop */
while (true) { while (true) {
uint32_t produce_index;
uint32_t consume_index;
#ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
uint32_t frame_length;
char *frame_buffer;
#endif
/* Wait for events */ /* Wait for events */
sc = rtems_event_receive( sc = rtems_event_receive(
LPC_ETH_EVENT_INITIALIZE LPC_ETH_EVENT_STOP
| LPC_ETH_EVENT_STOP
| LPC_ETH_EVENT_TXSTART | LPC_ETH_EVENT_TXSTART
| LPC_ETH_EVENT_INTERRUPT, | LPC_ETH_EVENT_INTERRUPT,
RTEMS_EVENT_ANY | RTEMS_WAIT, RTEMS_EVENT_ANY | RTEMS_WAIT,
@ -839,57 +908,17 @@ static void lpc_eth_transmit_task(rtems_task_argument arg)
continue; continue;
} }
/* Initialize transmitter? */ LPE_LOCK(e);
if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) {
/* Disable transmit interrupts */
lpc_eth_disable_transmit_interrupts();
/* Disable transmitter */ /* Get indices */
lpc_eth->command &= ~ETH_CMD_TX_ENABLE; produce_index = e->tx_produce_index;
consume_index = e->tx_consume_index;
/* Wait for inactive status */ #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA
while ((lpc_eth->status & ETH_STAT_TX_ACTIVE) != 0) { /* Fresh frame length and buffer start */
/* Wait */ frame_length = 0;
} frame_buffer = (char *) desc [produce_index].start;
#endif
/* 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 */ /* Free consumed fragments */
while (true) { while (true) {
@ -1074,6 +1103,10 @@ static void lpc_eth_transmit_task(rtems_task_argument arg)
} }
} }
/* Save indices */
e->tx_produce_index = produce_index;
e->tx_consume_index = consume_index;
/* No more fragments? */ /* No more fragments? */
if (m == NULL) { if (m == NULL) {
/* Interface is now inactive */ /* Interface is now inactive */
@ -1084,6 +1117,8 @@ static void lpc_eth_transmit_task(rtems_task_argument arg)
/* Enable transmit interrupts */ /* Enable transmit interrupts */
lpc_eth_enable_transmit_interrupts(); lpc_eth_enable_transmit_interrupts();
} }
LPE_UNLOCK(e);
} }
} }
@ -1418,8 +1453,8 @@ static int lpc_eth_up_or_down(lpc_eth_driver_entry *e, bool up)
lpc_eth->mac1 = 0x03; lpc_eth->mac1 = 0x03;
/* Initialize tasks */ /* Initialize tasks */
lpc_eth_control_request(e, e->receive_task, LPC_ETH_EVENT_INITIALIZE); lpc_eth_control_request(e, e->receive_task, LPC_ETH_EVENT_INIT_RX);
lpc_eth_control_request(e, e->transmit_task, LPC_ETH_EVENT_INITIALIZE); lpc_eth_initialize_transmit(e);
/* Install interrupt handler */ /* Install interrupt handler */
sc = rtems_interrupt_handler_install( sc = rtems_interrupt_handler_install(