/** \brief Attempt to allocate and requeue a new pbuf for RX * * \param[in] netif Pointer to the netif structure * \returns 1 if a packet was allocated and requeued, otherwise 0 */ s32_t lpc_rx_queue(struct netif *netif) { struct lpc_enetdata *lpc_enetif = netif->state; struct pbuf *p; s32_t queued = 0; /* Attempt to requeue as many packets as possible */ while (lpc_enetif->rx_free_descs > 0) { /* Allocate a pbuf from the pool. We need to allocate at the maximum size as we don't know the size of the yet to be received packet. */ p = pbuf_alloc(PBUF_RAW, (u16_t) EMAC_ETH_MAX_FLEN, PBUF_RAM); if (p == NULL) { LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, ("lpc_rx_queue: could not allocate RX pbuf (free desc=%d)\r\n", lpc_enetif->rx_free_descs)); return queued; } /* pbufs allocated from the RAM pool should be non-chained. */ LWIP_ASSERT("lpc_rx_queue: pbuf is not contiguous (chained)", pbuf_clen(p) <= 1); /* Queue packet */ lpc_rxqueue_pbuf(lpc_enetif, p); /* Update queued count */ queued++; } return queued; }
/** \brief Allocates a pbuf and returns the data from the incoming packet. * * \param[in] netif the lwip network interface structure for this lpc_enetif * \return a pbuf filled with the received packet (including MAC header) * NULL on memory error */ static struct pbuf *lpc_low_level_input(struct netif *netif) { struct lpc_enetdata *lpc_enetif = netif->state; struct pbuf *p = NULL; u32_t idx, length; u16_t origLength; #ifdef LOCK_RX_THREAD #if NO_SYS == 0 /* Get exclusive access */ sys_mutex_lock(&lpc_enetif->TXLockMutex); #endif #endif /* Monitor RX overrun status. This should never happen unless (possibly) the internal bus is behing held up by something. Unless your system is running at a very low clock speed or there are possibilities that the internal buses may be held up for a long time, this can probably safely be removed. */ if (LPC_EMAC->IntStatus & EMAC_INT_RX_OVERRUN) { LINK_STATS_INC(link.err); LINK_STATS_INC(link.drop); /* Temporarily disable RX */ LPC_EMAC->MAC1 &= ~EMAC_MAC1_REC_EN; /* Reset the RX side */ LPC_EMAC->MAC1 |= EMAC_MAC1_RES_RX; LPC_EMAC->IntClear = EMAC_INT_RX_OVERRUN; /* De-allocate all queued RX pbufs */ for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) { if (lpc_enetif->rxb[idx] != NULL) { pbuf_free(lpc_enetif->rxb[idx]); lpc_enetif->rxb[idx] = NULL; } } /* Start RX side again */ lpc_rx_setup(lpc_enetif); /* Re-enable RX */ LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; #ifdef LOCK_RX_THREAD #if NO_SYS == 0 sys_mutex_unlock(&lpc_enetif->TXLockMutex); #endif #endif return NULL; } /* Determine if a frame has been received */ length = 0; idx = LPC_EMAC->RxConsumeIndex; if (LPC_EMAC->RxProduceIndex != idx) { /* Handle errors */ if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR | EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_LEN_ERR)) { #if LINK_STATS if (lpc_enetif->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR | EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR)) LINK_STATS_INC(link.chkerr); if (lpc_enetif->prxs[idx].statusinfo & EMAC_RINFO_LEN_ERR) LINK_STATS_INC(link.lenerr); #endif /* Drop the frame */ LINK_STATS_INC(link.drop); /* Re-queue the pbuf for receive */ lpc_enetif->rx_free_descs++; p = lpc_enetif->rxb[idx]; lpc_enetif->rxb[idx] = NULL; lpc_rxqueue_pbuf(lpc_enetif, p); LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, ("lpc_low_level_input: Packet dropped with errors (0x%x)\r\n", lpc_enetif->prxs[idx].statusinfo)); p = NULL; } else { /* A packet is waiting, get length */ length = (lpc_enetif->prxs[idx].statusinfo & 0x7FF) + 1; /* Zero-copy */ p = lpc_enetif->rxb[idx]; origLength = p->len; p->len = (u16_t) length; /* Free pbuf from descriptor */ lpc_enetif->rxb[idx] = NULL; lpc_enetif->rx_free_descs++; /* Attempt to queue new buffer(s) */ if (lpc_rx_queue(lpc_enetif->netif) == 0) { /* Drop the frame due to OOM. */ LINK_STATS_INC(link.drop); /* Re-queue the pbuf for receive */ p->len = origLength; lpc_rxqueue_pbuf(lpc_enetif, p); LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, ("lpc_low_level_input: Packet index %d dropped for OOM\r\n", idx)); #ifdef LOCK_RX_THREAD #if NO_SYS == 0 sys_mutex_unlock(&lpc_enetif->TXLockMutex); #endif #endif return NULL; } LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE, ("lpc_low_level_input: Packet received: %p, size %d (index=%d)\r\n", p, length, idx)); /* Save size */ p->tot_len = (u16_t) length; LINK_STATS_INC(link.recv); } } #ifdef LOCK_RX_THREAD #if NO_SYS == 0 sys_mutex_unlock(&lpc_enetif->TXLockMutex); #endif #endif return p; }
/* Gets data from queue and forwards to LWIP */ static struct pbuf *lpc_low_level_input(struct netif *netif) { struct lpc_enetdata *lpc_netifdata = netif->state; u32_t status, ridx; int rxerr = 0; struct pbuf *p; #ifdef LOCK_RX_THREAD #if NO_SYS == 0 /* Get exclusive access */ sys_mutex_lock(&lpc_netifdata->TXLockMutex); #endif #endif /* If there are no used descriptors, then this call was not for a received packet, try to setup some descriptors now */ if (lpc_netifdata->rx_free_descs == LPC_NUM_BUFF_RXDESCS) { lpc_rx_queue(netif); #ifdef LOCK_RX_THREAD #if NO_SYS == 0 sys_mutex_unlock(&lpc_netifdata->TXLockMutex); #endif #endif return NULL; } /* Get index for next descriptor with data */ ridx = lpc_netifdata->rx_get_idx; /* Return if descriptor is still owned by DMA */ if (lpc_netifdata->prdesc[ridx].STATUS & RDES_OWN) { #ifdef LOCK_RX_THREAD #if NO_SYS == 0 sys_mutex_unlock(&lpc_netifdata->TXLockMutex); #endif #endif return NULL; } /* Get address of pbuf for this descriptor */ p = lpc_netifdata->rxpbufs[ridx]; /* Get receive packet status */ status = lpc_netifdata->prdesc[ridx].STATUS; /* Check packet for errors */ if (status & RDES_ES) { LINK_STATS_INC(link.drop); /* Error conditions that cause a packet drop */ if (status & intMask) { LINK_STATS_INC(link.err); rxerr = 1; } else /* Length error check needs qualification */ if ((status & (RDES_LE | RDES_FT)) == RDES_LE) { LINK_STATS_INC(link.lenerr); rxerr = 1; } else /* CRC error check needs qualification */ if ((status & (RDES_CE | RDES_LS)) == (RDES_CE | RDES_LS)) { LINK_STATS_INC(link.chkerr); rxerr = 1; } /* Descriptor error check needs qualification */ if ((status & (RDES_DE | RDES_LS)) == (RDES_DE | RDES_LS)) { LINK_STATS_INC(link.err); rxerr = 1; } else /* Dribble bit error only applies in half duplex mode */ if ((status & RDES_DE) && (!(LPC_ETHERNET->MAC_CONFIG & MAC_CFG_DM))) { LINK_STATS_INC(link.err); rxerr = 1; } } /* Increment free descriptor count and next get index */ lpc_netifdata->rx_free_descs++; ridx++; if (ridx >= LPC_NUM_BUFF_RXDESCS) { ridx = 0; } lpc_netifdata->rx_get_idx = ridx; /* If an error occurred, just re-queue the pbuf */ if (rxerr) { lpc_rxqueue_pbuf(lpc_netifdata, p); p = NULL; LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE, ("lpc_low_level_input: RX error condition status 0x%08x\n", status)); } else { /* Attempt to queue a new pbuf for the descriptor */ lpc_rx_queue(netif); /* Get length of received packet */ p->len = p->tot_len = (u16_t) RDES_FLMSK(status); LINK_STATS_INC(link.recv); LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE, ("lpc_low_level_input: Packet received, %d bytes, " "status 0x%08x\n", p->len, status)); } /* (Re)start receive polling */ LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1; #ifdef LOCK_RX_THREAD #if NO_SYS == 0 /* Get exclusive access */ sys_mutex_unlock(&lpc_netifdata->TXLockMutex); #endif #endif return p; }
/* Allocates a pbuf and returns the data from the incoming packet */ STATIC struct pbuf *lpc_low_level_input(struct netif *netif) { lpc_enetdata_t *lpc_enetif = netif->state; struct pbuf *p = NULL; u32_t idx, length; #ifdef LOCK_RX_THREAD #if NO_SYS == 0 /* Get exclusive access */ sys_mutex_lock(&lpc_enetif->rx_lock_mutex); #endif #endif /* Monitor RX overrun status. This should never happen unless (possibly) the internal bus is behing held up by something. Unless your system is running at a very low clock speed or there are possibilities that the internal buses may be held up for a long time, this can probably safely be removed. */ if (Chip_ENET_GetIntStatus(LPC_ETHERNET) & ENET_INT_RXOVERRUN) { LINK_STATS_INC(link.err); LINK_STATS_INC(link.drop); /* Temporarily disable RX */ Chip_ENET_RXDisable(LPC_ETHERNET); /* Reset the RX side */ Chip_ENET_ResetRXLogic(LPC_ETHERNET); Chip_ENET_ClearIntStatus(LPC_ETHERNET, ENET_INT_RXOVERRUN); /* De-allocate all queued RX pbufs */ for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) { if (lpc_enetif->rxb[idx] != NULL) { pbuf_free(lpc_enetif->rxb[idx]); lpc_enetif->rxb[idx] = NULL; } } /* Start RX side again */ lpc_rx_setup(lpc_enetif); /* Re-enable RX */ Chip_ENET_RXEnable(LPC_ETHERNET); #ifdef LOCK_RX_THREAD #if NO_SYS == 0 sys_mutex_unlock(&lpc_enetif->rx_lock_mutex); #endif #endif return NULL; } /* Determine if a frame has been received */ length = 0; idx = Chip_ENET_GetRXConsumeIndex(LPC_ETHERNET); if (!Chip_ENET_IsRxEmpty(LPC_ETHERNET)) { /* Handle errors */ if (lpc_enetif->prxs[idx].StatusInfo & (ENET_RINFO_CRC_ERR | ENET_RINFO_SYM_ERR | ENET_RINFO_ALIGN_ERR | ENET_RINFO_LEN_ERR)) { #if LINK_STATS if (lpc_enetif->prxs[idx].StatusInfo & (ENET_RINFO_CRC_ERR | ENET_RINFO_SYM_ERR | ENET_RINFO_ALIGN_ERR)) { LINK_STATS_INC(link.chkerr); } if (lpc_enetif->prxs[idx].StatusInfo & ENET_RINFO_LEN_ERR) { LINK_STATS_INC(link.lenerr); } #endif /* Drop the frame */ LINK_STATS_INC(link.drop); /* Re-queue the pbuf for receive */ lpc_enetif->rx_free_descs++; p = lpc_enetif->rxb[idx]; lpc_enetif->rxb[idx] = NULL; lpc_rxqueue_pbuf(lpc_enetif, p); LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE, ("lpc_low_level_input: Packet dropped with errors (0x%x)\n", lpc_enetif->prxs[idx].StatusInfo)); p = NULL; } else { /* A packet is waiting, get length */ length = ENET_RINFO_SIZE(lpc_enetif->prxs[idx].StatusInfo) - 4; /* Remove FCS */ /* Zero-copy */ p = lpc_enetif->rxb[idx]; p->len = (u16_t) length; /* Free pbuf from desriptor */ lpc_enetif->rxb[idx] = NULL; lpc_enetif->rx_free_descs++; /* Queue new buffer(s) */ if (lpc_rx_queue(lpc_enetif->pnetif) == 0) { /* Re-queue the pbuf for receive */ lpc_rxqueue_pbuf(lpc_enetif, p); /* Drop the frame */ LINK_STATS_INC(link.drop); LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE, ("lpc_low_level_input: Packet dropped since it could not allocate Rx Buffer\n")); p = NULL; } else { LWIP_DEBUGF(EMAC_DEBUG | LWIP_DBG_TRACE, ("lpc_low_level_input: Packet received: %p, size %d (index=%d)\n", p, length, idx)); /* Save size */ p->tot_len = (u16_t) length; LINK_STATS_INC(link.recv); } } /* Update Consume index */ Chip_ENET_IncRXConsumeIndex(LPC_ETHERNET); } #ifdef LOCK_RX_THREAD #if NO_SYS == 0 sys_mutex_unlock(&lpc_enetif->rx_lock_mutex); #endif #endif return p; }