diff --git a/port/ethernetif.c b/port/ethernetif.c index 75d3463..6604108 100644 --- a/port/ethernetif.c +++ b/port/ethernetif.c @@ -20,6 +20,7 @@ struct ethernetif { ETH_DMADESCTypeDef* DMARxDescToGet; + ETH_DMADESCTypeDef* DMARxDescToRead; ETH_DMADESCTypeDef* DMATxDescToSet; }; @@ -29,7 +30,6 @@ __attribute__((aligned(4))) uint8_t MACRxBuf[ETH_RXBUFNB * ETH_RX_BUF_SZE]; __attribute__((aligned(4))) uint8_t MACTxBuf[ETH_TXBUFNB * ETH_TX_BUF_SZE]; static volatile bool g_link_interrupt_flag = false; -static volatile bool g_packet_received_flag = false; static struct ethernetif eth_state; static void low_level_init(struct netif* netif); @@ -114,8 +114,9 @@ static void low_level_init(struct netif* netif) { // init RX descriptors ethernetif->DMARxDescToGet = DMARxDscrTab; + ethernetif->DMARxDescToRead = DMARxDscrTab; for (int i = 0; i < ETH_RXBUFNB; i++) { - DMARxDscrTab[i].Status = 0; + DMARxDscrTab[i].Status = ETH_DMARxDesc_OWN; DMARxDscrTab[i].Buffer1Addr = (uint32_t)&MACRxBuf[i * ETH_RX_BUF_SZE]; DMARxDscrTab[i].Buffer2NextDescAddr = (uint32_t)&DMARxDscrTab[(i + 1) % ETH_RXBUFNB]; @@ -167,55 +168,42 @@ static err_t low_level_output(struct netif* netif, struct pbuf* p) { static struct pbuf* low_level_input(struct netif* netif) { struct ethernetif* ethernetif = netif->state; + struct pbuf* p = NULL; - uint16_t len = ETH10M->ERXLN; - - if (len < MIN_ETH_FRAME_SIZE || len > ETH_MAX_PACKET_SIZE) { - LINK_STATS_INC(link.lenerr); - ETH10M->ECON1 |= RB_ETH_ECON1_RXEN; + // if OWN bit is set, it's still owned by DMA and no packet rdy + if (ethernetif->DMARxDescToRead->Status & ETH_DMARxDesc_OWN) { return NULL; } - uint8_t* current_rx_buffer_ptr = - (uint8_t*)ethernetif->DMARxDescToGet->Buffer1Addr; + // packet ready + uint32_t len = (ethernetif->DMARxDescToRead->Status & ETH_DMARxDesc_FL) >> 16; - struct pbuf* p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); if (p != NULL) { + uint8_t* buffer = (uint8_t*)ethernetif->DMARxDescToRead->Buffer1Addr; uint32_t offset = 0; for (struct pbuf* q = p; q != NULL; q = q->next) { - memcpy(q->payload, current_rx_buffer_ptr + offset, q->len); + memcpy(q->payload, buffer + offset, q->len); offset += q->len; } LINK_STATS_INC(link.recv); - MIB2_STATS_NETIF_ADD(netif, ifinoctets, len); } else { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); - MIB2_STATS_NETIF_INC(netif, ifindiscards); } - // move to next descriptor - ethernetif->DMARxDescToGet = - (ETH_DMADESCTypeDef*)ethernetif->DMARxDescToGet->Buffer2NextDescAddr; - ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr; - ETH10M->ECON1 |= RB_ETH_ECON1_RXEN; + // give buffer back to DMA + ethernetif->DMARxDescToRead->Status = ETH_DMARxDesc_OWN; + // advance read pointer to the next descriptor in the ring + ethernetif->DMARxDescToRead = + (ETH_DMADESCTypeDef*)ethernetif->DMARxDescToRead->Buffer2NextDescAddr; return p; } void ethernetif_input(struct netif* netif) { - if (!g_packet_received_flag) { - return; - } - - NVIC_DisableIRQ(ETH_IRQn); - if (g_packet_received_flag) { - g_packet_received_flag = false; - } - NVIC_EnableIRQ(ETH_IRQn); - - struct pbuf* p = low_level_input(netif); - if (p != NULL) { + struct pbuf* p; + while ((p = low_level_input(netif)) != NULL) { if (netif->input(p, netif) != ERR_OK) { pbuf_free(p); } @@ -245,10 +233,31 @@ void ethernetif_link_poll(struct netif* netif) { void ETH_IRQHandler(void) __attribute__((interrupt)) __attribute__((used)); void ETH_IRQHandler(void) { uint32_t flags = ETH10M->EIR; + struct ethernetif* ethernetif = ð_state; if (flags & RB_ETH_EIR_RXIF) { - g_packet_received_flag = true; ETH10M->EIR = RB_ETH_EIR_RXIF; + + // descriptor should be owned by DMA + if (ethernetif->DMARxDescToGet->Status & ETH_DMARxDesc_OWN) { + ETH_DMADESCTypeDef* next_desc = + (ETH_DMADESCTypeDef*)ethernetif->DMARxDescToGet->Buffer2NextDescAddr; + + // if next descriptor OWN bit is 0, ring is full and we must drop + if (!(next_desc->Status & ETH_DMARxDesc_OWN)) { + LINK_STATS_INC(link.drop); + } else { + // process and re-arm + ethernetif->DMARxDescToGet->Status &= ~ETH_DMARxDesc_OWN; + // write packet len into status field for CPU + ethernetif->DMARxDescToGet->Status |= + (ETH_DMARxDesc_FS | ETH_DMARxDesc_LS | (ETH10M->ERXLN << 16)); + // advance descripotor ptr + ethernetif->DMARxDescToGet = next_desc; + // re-arm receiver with new emtpy buf + ETH10M->ERXST = (uint32_t)ethernetif->DMARxDescToGet->Buffer1Addr; + } + } } if (flags & RB_ETH_EIR_TXIF) {