Exemplo n.º 1
0
/** \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;
}
Exemplo n.º 2
0
/** \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;
}