1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2026-01-01 01:41:18 +01:00

Merge pull request #16683 from dylad/pr/cpu/sam0/eth-fix

cpu/sam0: improve ethernet driver resilience
This commit is contained in:
benpicco 2021-07-27 14:02:31 +02:00 committed by GitHub
commit 666a45729c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 14 deletions

View File

@ -90,6 +90,19 @@ static uint8_t rx_idx;
static uint8_t rx_buf[ETH_RX_BUFFER_COUNT][ETH_RX_BUFFER_SIZE] __attribute__((aligned(GMAC_BUF_ALIGNMENT)));
static uint8_t tx_buf[ETH_TX_BUFFER_COUNT][ETH_TX_BUFFER_SIZE] __attribute__((aligned(GMAC_BUF_ALIGNMENT)));
extern sam0_eth_netdev_t _sam0_eth_dev;
/* Flush our reception buffers and reset reception internal mechanism,
this function may be call from ISR context */
void sam0_clear_rx_buffers(void)
{
for (int i=0; i<ETH_RX_BUFFER_COUNT; i++) {
rx_desc[i].address &= ~DESC_RX_ADDR_OWNSHP;
}
rx_idx = 0;
rx_curr = rx_desc;
GMAC->RBQB.reg = (uint32_t) rx_desc;
}
static void _init_desc_buf(void)
{
@ -193,13 +206,33 @@ int sam0_eth_send(const struct iolist *iolist)
return len;
}
static int _try_receive(char* data, int max_len, int block)
static int _try_receive(char* data, unsigned max_len, int block)
{
(void)block;
unsigned rxlen = 0;
uint16_t idx = rx_idx;
/* Ensure we are at the beginning of the new frame */
while (!(rx_curr->address & DESC_RX_ADDR_OWNSHP) && (rx_curr->status & DESC_RX_STATUS_STA_FRAME)) {}
uint8_t tmp = ETH_RX_BUFFER_COUNT;
/* Check if the current rx descriptor contains the beginning of
a new frame, iterates over all our RX buffers if not.
If there is no new frame (because we may have flush our RX
buffers due to BNA interrupt), return an error to netdev so
we can move forward */
do {
if ((rx_curr->address & DESC_RX_ADDR_OWNSHP)
&& (rx_curr->status & DESC_RX_STATUS_STA_FRAME)) {
break;
}
else {
idx = (idx+1) % ETH_RX_BUFFER_COUNT;
rx_curr = &rx_desc[idx];
tmp--;
}
} while (tmp > 0);
if (tmp == 0) {
return -ENOBUFS;
}
for (unsigned cpt=0; cpt < ETH_RX_BUFFER_COUNT; cpt++) {
/* Get the length of the received frame */
@ -210,6 +243,11 @@ static int _try_receive(char* data, int max_len, int block)
if (max_len) {
/* If buffer available, copy data into it */
if (data) {
/* If provided buffer is smaller than the received frame,
drop it as netdev request */
if (rxlen + len > max_len) {
return -ENOBUFS;
}
memcpy(&data[rxlen], rx_buf[idx], len);
}
/* Tell the GMAC IP that we don't need this frame anymore */
@ -226,16 +264,22 @@ static int _try_receive(char* data, int max_len, int block)
idx = (idx + 1) % ETH_RX_BUFFER_COUNT;
rx_curr = &rx_desc[idx];
}
/* restore the previous index if packets were not released */
if (!max_len) {
}
/* restore the previous index if packets were not released */
if (!max_len) {
rx_curr = &rx_desc[rx_idx];
}
}
/* Point to the next buffer as GMAC IP will likely used it
to store the next frame */
else {
else {
rx_idx = (idx+1) % ETH_RX_BUFFER_COUNT;
rx_curr = &rx_desc[rx_idx];
}
/* If provided buffer is smaller than the received frame,
drop it as netdev request */
if (data != NULL && rxlen > max_len) {
return -ENOBUFS;
}
return rxlen;

View File

@ -40,6 +40,7 @@ extern int sam0_eth_send(const struct iolist *iolist);
extern int sam0_eth_receive_blocking(char *data, unsigned max_len);
extern void sam0_eth_set_mac(const eui48_t *mac);
extern void sam0_eth_get_mac(char *out);
extern void sam0_clear_rx_buffers(void);
/* SAM0 CPUs only have one GMAC IP, so it is safe to
statically defines one in this file */
@ -140,24 +141,29 @@ void sam0_eth_setup(netdev_t* netdev)
netdev_register(netdev, NETDEV_SAM0_ETH, 0);
}
/* TODO: rework the whole isr management... */
void isr_gmac(void)
{
uint32_t isr;
uint32_t tsr;
uint32_t rsr;
isr = GMAC->ISR.reg;
tsr = GMAC->TSR.reg;
rsr = GMAC->RSR.reg;
(void)isr;
/* New frame received, signal it to netdev */
if (rsr & GMAC_RSR_REC) {
netdev_trigger_event_isr(_sam0_eth_dev.netdev);
}
GMAC->TSR.reg = tsr;
/* Buffers Not Available, this can occur if there is a heavy traffic
on the network. In this case, disable the GMAC reception, flush
our internal buffers and re-enable the reception. This will drop
a few packets but it allows the GMAC IP to remains functional */
if (rsr & GMAC_RSR_BNA) {
GMAC->NCR.reg &= ~GMAC_NCR_RXEN;
sam0_clear_rx_buffers();
GMAC->NCR.reg |= GMAC_NCR_RXEN;
}
GMAC->RSR.reg = rsr;
GMAC->ISR.reg = isr;
cortexm_isr_end();
}