⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lpc17_emac.c

📁 NXPl788上lwip的无操作系统移植,基于Embest开发板
💻 C
📖 第 1 页 / 共 3 页
字号:
			lpc_enetdata->rx_free_descs++;

			LWIP_DEBUGF(UDP_LPC_EMAC | 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);
		}
	}

	return p;  
}

#else /* Copied RX obuf driver starts here */
/** \brief  Sets up the RX descriptor ring buffers.

    This function sets up the descriptor list used for receive packets.

    \param [in]  lpc_enetdata_def  Pointer to driver data structure
	\returns                   Always returns ERR_OK
 */
static err_t lpc_rx_setup(struct lpc_enetdata_def *lpc_enetdata)
{
	s32_t idx;

	/* Setup pointers to RX structures */
	LPC_EMAC->RxDescriptor = (u32_t) &lpc_enetdata->prxd[0];
	LPC_EMAC->RxStatus = (u32_t) &lpc_enetdata->prxs[0];
	LPC_EMAC->RxDescriptorNumber = LPC_NUM_BUFF_RXDESCS - 1;

	/* Build RX descriptors */
	for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
		/* Setup DMA RX descriptor */
		lpc_enetdata->prxd[idx].packet = (u32_t) &lpc_enetdata->lpc_rx_buffs[idx][0];
		lpc_enetdata->prxd[idx].control = EMAC_RCTRL_INT |
			(EMAC_ETH_MAX_FLEN - 1);
		lpc_enetdata->prxs[idx].statusinfo = 0xFFFFFFFF;
		lpc_enetdata->prxs[idx].statushashcrc = 0xFFFFFFFF;
	}

	return ERR_OK;
}

/** \brief  Allocates a pbuf and returns the data from the incoming packet.

    \param 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_def *lpc_enetdata = netif->state;
	struct pbuf *p = NULL, *q;
	u32_t idx, length;
	u8_t *src;

	/* 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;

		/* Start RX side again */
		lpc_rx_setup(lpc_enetdata);

		/* Re-enable RX */
		LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN;

		return NULL;
	}

	/* Determine if a frame has been received */
	idx = LPC_EMAC->RxConsumeIndex;
	if (LPC_EMAC->RxProduceIndex != idx) {
		/* Handle errors */
		if (lpc_enetdata->prxs[idx].statusinfo & (EMAC_RINFO_NO_DESCR |
			EMAC_RINFO_ALIGN_ERR | EMAC_RINFO_LEN_ERR | EMAC_RINFO_SYM_ERR |
			EMAC_RINFO_CRC_ERR)) {
#if LINK_STATS
			if (lpc_enetdata->prxs[idx].statusinfo & (EMAC_RINFO_CRC_ERR |
				EMAC_RINFO_SYM_ERR | EMAC_RINFO_ALIGN_ERR))
				LINK_STATS_INC(link.chkerr);
			if (lpc_enetdata->prxs[idx].statusinfo & EMAC_RINFO_LEN_ERR)
				LINK_STATS_INC(link.lenerr);
#endif

			/* Drop the frame */
			LINK_STATS_INC(link.drop);

			LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
				("lpc_low_level_input: Packet dropped with errors\n"));
		}
		else {
			/* A packet is waiting, get length */
			length = (lpc_enetdata->prxs[idx].statusinfo & 0x7FF) + 1;

			/* Allocate a pbuf chain of pbufs from the pool. */
			p = pbuf_alloc(PBUF_RAW, (u16_t) length, PBUF_POOL);
			if (p == NULL) {
				/* Buffer in hardware is not lost, but cannot get packet now */
				LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
					("lpc_low_level_input: Could not allocate input pbuf\n"));
				return NULL;
			}

			/* Copy buffer */
			src = (u8_t *) lpc_enetdata->prxd[idx].packet;
		    for(q = p; q != NULL; q = q->next) {
				MEMCPY((u8_t *) q->payload, src, q->len);
				src += q->len;
			}

			LWIP_DEBUGF(UDP_LPC_EMAC | 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);
		}

			idx++;
			if (idx >= LPC_NUM_BUFF_RXDESCS)
				idx = 0;
			LPC_EMAC->RxConsumeIndex = idx;
	}

	return p;  
}
#endif /* End of RX copied or zero-copy driver section */

/** \brief  Attempt to read a packet from the EMAC interface.

    \param[in] netif the lwip network interface structure for this lpc_enetif
 */
void lpc_enetif_input(struct netif *netif)
{
	struct lpc_enetif *lpc_enetif = netif->state;
	struct eth_hdr *ethhdr;
	struct pbuf *p;

	/* move received packet into a new pbuf */
	p = lpc_low_level_input(netif);
	if (p == NULL)
		return;

	/* points to packet payload, which starts with an Ethernet header */
	ethhdr = p->payload;

	switch (htons(ethhdr->type)) {
		case ETHTYPE_IP:
		case ETHTYPE_ARP:
#if PPPOE_SUPPORT
		case ETHTYPE_PPPOEDISC:
		case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
			/* full packet send to tcpip_thread to process */
			if (netif->input(p, netif) != ERR_OK) {
				LWIP_DEBUGF(NETIF_DEBUG, ("lpc_enetif_input: IP input error\n"));
				/* Free buffer */
				pbuf_free(p);
			}
			break;

		default:
			/* Return buffer */
			pbuf_free(p);
			break;
	}
}

/** \brief  Determine if the passed address is usable for the ethernet
            DMA controller.

    \param [in] addr Address of packet to check for DMA safe operation
    \return          1 if the packet address is not safe, otherwise 0
 */
static s32_t lpc_packet_addr_notsafe(void *addr) {
	/* Check for legal address ranges */
	if ((((u32_t) addr >= 0x20000000) && ((u32_t) addr < 0x20008000)) ||
		(((u32_t) addr >= 0x80000000) && ((u32_t) addr < 0xF0000000)))
		return 0;

	return 1;
}

#if LPC_PBUF_TX_ZEROCOPY
/** \brief  Sets up the TX descriptor ring buffers.

    This function sets up the descriptor list used for transmit packets.

    \param [in]      lpc_enetdata_def  Pointer to driver data structure
 */
static err_t lpc_tx_setup(struct lpc_enetdata_def *lpc_enetdata)
{
	s32_t idx;

	/* Setup pointers to TX structures */
	LPC_EMAC->TxDescriptor = (u32_t) &lpc_enetdata->ptxd[0];
	LPC_EMAC->TxStatus = (u32_t) &lpc_enetdata->ptxs[0];
	LPC_EMAC->TxDescriptorNumber = LPC_NUM_BUFF_TXDESCS - 1;

	lpc_enetdata->lpc_last_tx_idx = 0;

	/* Build TX descriptors for local buffers */
	for (idx = 0; idx < LPC_NUM_BUFF_TXDESCS; idx++) {
		lpc_enetdata->ptxd[idx].control = 0;
		lpc_enetdata->ptxs[idx].statusinfo = 0xFFFFFFFF;
	}

	return ERR_OK;
}

/** \brief  Free TX buffers that are complete

    \param [in] lpc_enetdata_def  Pointer to driver data structure
    \param [in] cidx  EMAC current descriptor comsumer index
 */
static void lpc_tx_reclaim_st(struct lpc_enetdata_def *lpc_enetdata, u32_t cidx)
{
	while (cidx != lpc_enetdata->lpc_last_tx_idx) {
		if (lpc_enetdata->txb[lpc_enetdata->lpc_last_tx_idx] != NULL) {
			LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
				("lpc_tx_reclaim_st: Freeing packet %p (index %d)\n",
				lpc_enetdata->txb[lpc_enetdata->lpc_last_tx_idx],
				lpc_enetdata->lpc_last_tx_idx));
			pbuf_free(lpc_enetdata->txb[lpc_enetdata->lpc_last_tx_idx]);
		 	lpc_enetdata->txb[lpc_enetdata->lpc_last_tx_idx] = NULL;
		}

		lpc_enetdata->lpc_last_tx_idx++;
		if (lpc_enetdata->lpc_last_tx_idx >= LPC_NUM_BUFF_TXDESCS)
			lpc_enetdata->lpc_last_tx_idx = 0;
	}
}

/** \brief  User call for freeingTX buffers that are complete

    \param [in] netif the lwip network interface structure for this lpc_enetif
 */
void lpc_tx_reclaim(struct netif *netif)
{
	lpc_tx_reclaim_st((struct lpc_enetdata_def *) netif->state,
		LPC_EMAC->TxConsumeIndex);
}

 /** \brief  Polls if an available TX descriptor is ready. Can be used to
             determine if the low level transmit function will block.

    \param [in] netif the lwip network interface structure for this lpc_enetif
    \return 0 if no descriptors are read, or >0
 */
s32_t lpc_tx_ready(struct netif *netif)
{
	s32_t fb;
	u32_t idx, cidx;

	cidx = LPC_EMAC->TxConsumeIndex;
	lpc_tx_reclaim_st((struct lpc_enetdata_def *) netif->state, cidx);

	idx = LPC_EMAC->TxProduceIndex;

	/* Determine number of free buffers */
	if (idx == cidx)
		fb = LPC_NUM_BUFF_TXDESCS;
	else if (cidx > idx)
		fb = (LPC_NUM_BUFF_TXDESCS - 1) -
			((idx + LPC_NUM_BUFF_TXDESCS) - cidx);
	else
		fb = (LPC_NUM_BUFF_TXDESCS - 1) - (cidx - idx);

	return fb;
}

/** \brief  Low level output of a packet. Never call this from an
            interrupt context, as it may block until TX descriptors
			become available.

    \param netif the lwip network interface structure for this lpc_enetif
    \param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
    \return ERR_OK if the packet could be sent
           an err_t value if the packet couldn't be sent
 */
static err_t lpc_low_level_output(struct netif *netif, struct pbuf *p)
{
	struct lpc_enetdata_def *lpc_enetdata = netif->state;
	struct pbuf *q;
	u8_t *dst;
	u32_t idx, sz = 0;
	err_t err = ERR_OK;
	struct pbuf *np;
	u32_t dn, notdmasafe = 0;

	/* Error handling for TX underruns. This should never happen unless
	   something is holding the bus or the clocks are going too slow. It
	   can probably be safely removed. */
 	if (LPC_EMAC->IntStatus & EMAC_INT_TX_UNDERRUN) {
		LINK_STATS_INC(link.err);
		LINK_STATS_INC(link.drop);

		/* Reset the TX side */
		LPC_EMAC->MAC1 |= EMAC_MAC1_RES_TX;
		LPC_EMAC->IntClear = EMAC_INT_TX_UNDERRUN;

		/* De-allocate all queued TX pbufs */
		for (idx = 0; idx < LPC_NUM_BUFF_RXDESCS; idx++) {
			if (lpc_enetdata->txb[idx] != NULL) {
				pbuf_free(lpc_enetdata->txb[idx]);
				lpc_enetdata->txb[idx] = NULL;
			}
		}

		/* Start TX side again */
		lpc_tx_setup(lpc_enetdata);
	}

	/* Zero-copy TX buffers may be fragmented across mutliple payload
	   chains. Determine the number of descriptors needed for the
	   transfer. The pbuf chaining can be a mess! */
	dn = (u32_t) pbuf_clen(p);

	/* Test to make sure packet addresses are DMA safe. A DMA safe
	   address is once that uses external memory or periphheral RAM.
	   IRAM and FLASH are not safe! */
	for (q = p; q != NULL; q = q->next)
		notdmasafe += lpc_packet_addr_notsafe(q->payload);

#if LPC_TX_PBUF_BOUNCE_EN==1
	/* If the pbuf is not DMA safe, a new bounce buffer (pbuf) will be
	   created that will be used instead. This requires an copy from the
	   non-safe DMA region to the new pbuf */
	if (notdmasafe) {
		/* Allocate a pbuf in DMA memory */
		np = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
		if (np == NULL)
			return ERR_MEM;	

		/* This buffer better be contiguous! */
		LWIP_ASSERT("lpc_low_level_output: New transmit pbuf is chained",
			(pbuf_clen(np) == 1));

		/* Copy to DMA safe pbuf */
		dst = (u8_t *) np->payload;
	 	for(q = p; q != NULL; q = q->next) {
			/* Copy the buffer to the descriptor's buffer */
	  		MEMCPY(dst, (u8_t *) q->payload, q->len);
		  dst += q->len;
		}
		np->len = p->tot_len; 

		LWIP_DEBUGF(UDP_LPC_EMAC | LWIP_DBG_TRACE,
			("lpc_low_level_output: Switched to DMA safe buffer, old=%p, new=%p\n",
			q, np));

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -