Skip to content

Commit

Permalink
mimxrt/eth: Fix an Ethernet transmit error.
Browse files Browse the repository at this point in the history
Sometimes frames could not be sent immediately because the controller was
still busy with previous frames.  Then, an error was returned to lwip.
This fix adds a limited number of retries for this busy state, waiting
100µs before the next attempt.  Typically the transmit succeeds now at the
second attempt.

Second change: Reset the controller for a clean state after soft reset.
  • Loading branch information
robert-hh authored and dpgeorge committed Mar 8, 2022
1 parent 5ea85b7 commit b0d460c
Showing 1 changed file with 21 additions and 4 deletions.
25 changes: 21 additions & 4 deletions ports/mimxrt/eth.c
Expand Up @@ -174,7 +174,7 @@ void eth_irq_handler(ENET_Type *base, enet_handle_t *handle, enet_event_t event,
}
} while (status != kStatus_ENET_RxFrameEmpty);
} else {
ENET_ClearInterruptStatus(base, kENET_TxFrameInterrupt);
ENET_ClearInterruptStatus(base, ENET_TX_INTERRUPT | ENET_ERR_INTERRUPT);
}
}

Expand Down Expand Up @@ -279,6 +279,7 @@ void eth_init(eth_t *self, int mac_idx, const phy_operations_t *phy_ops, int phy
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("PHY Init failed."));
}

ENET_Reset(ENET);
ENET_GetDefaultConfig(&enet_config);
enet_config.miiSpeed = (enet_mii_speed_t)speed;
enet_config.miiDuplex = (enet_mii_duplex_t)duplex;
Expand Down Expand Up @@ -311,6 +312,22 @@ void eth_set_trace(eth_t *self, uint32_t value) {
/*******************************************************************************/
// ETH-LwIP bindings

STATIC err_t eth_send_frame_blocking(ENET_Type *base, enet_handle_t *handle, uint8_t *buffer, int len) {
status_t status;
int i;
#define XMIT_LOOP 10

// Try a few times to send the frame
for (i = XMIT_LOOP; i > 0; i--) {
status = ENET_SendFrame(base, handle, buffer, len);
if (status != kStatus_ENET_TxFrameBusy) {
break;
}
ticks_delay_us64(100);
}
return status;
}

STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
// This function should always be called from a context where PendSV-level IRQs are disabled
status_t status;
Expand All @@ -319,7 +336,7 @@ STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
eth_trace(netif->state, (size_t)-1, p, NETUTILS_TRACE_IS_TX | NETUTILS_TRACE_NEWLINE);

if (p->next == NULL) {
status = ENET_SendFrame(ENET, &g_handle, p->payload, p->len);
status = eth_send_frame_blocking(ENET, &g_handle, p->payload, p->len);
} else {
// frame consists of several parts. Copy them together and send them
size_t length = 0;
Expand All @@ -330,8 +347,8 @@ STATIC err_t eth_netif_output(struct netif *netif, struct pbuf *p) {
length += p->len;
p = p->next;
}
status = ENET_SendFrame(ENET, &g_handle, tx_frame, length);
}
status = eth_send_frame_blocking(ENET, &g_handle, tx_frame, length);
}
return status == kStatus_Success ? ERR_OK : ERR_BUF;
}

Expand Down

0 comments on commit b0d460c

Please sign in to comment.