Ejemplo n.º 1
0
/* Low level init of the MAC and PHY */
STATIC err_t low_level_init(struct netif *netif)
{
	lpc_enetdata_t *lpc_enetif = netif->state;
	err_t err = ERR_OK;

#if defined(USE_RMII)
	Chip_ENET_Init(LPC_ETHERNET, true);

#else
	Chip_ENET_Init(LPC_ETHERNET, false);
#endif

	/* Initialize the PHY */
	Chip_ENET_SetupMII(LPC_ETHERNET, Chip_ENET_FindMIIDiv(LPC_ETHERNET, 2500000), LPC_PHYDEF_PHYADDR);
#if defined(USE_RMII)
	if (lpc_phy_init(true, msDelay) != SUCCESS) {
		return ERROR;
	}
#else
	if (lpc_phy_init(false, msDelay) != SUCCESS) {
		return ERROR;
	}
#endif

	/* Save station address */
	Chip_ENET_SetADDR(LPC_ETHERNET, netif->hwaddr);

	/* Setup transmit and receive descriptors */
	if (lpc_tx_setup(lpc_enetif) != ERR_OK) {
		return ERR_BUF;
	}
	if (lpc_rx_setup(lpc_enetif) != ERR_OK) {
		return ERR_BUF;
	}

	/* Enable packet reception */
#if IP_SOF_BROADCAST_RECV
	Chip_ENET_EnableRXFilter(LPC_ETHERNET, ENET_RXFILTERCTRL_APE | ENET_RXFILTERCTRL_ABE);
#else
	Chip_ENET_EnableRXFilter(ENET_RXFILTERCTRL_APE);
#endif

	/* Clear and enable rx/tx interrupts */
	Chip_ENET_EnableInt(LPC_ETHERNET, RXINTGROUP | TXINTGROUP);

	/* Enable RX and TX */
	Chip_ENET_TXEnable(LPC_ETHERNET);
	Chip_ENET_RXEnable(LPC_ETHERNET);

	return err;
}
/* 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;
}