[U-Boot] [PATCH v2 10/14] net: emaclite: Use indirect access in emaclite_recv

Michal Simek michal.simek at xilinx.com
Thu Dec 17 13:09:23 CET 2015


When IP is configured with pong buffers, IP is receiving packets to ping
and then to pong buffer and than ping again.
The original logic in the driver remains there that when ping buffer is
free, pong buffer is checked too and return if both are free.

Signed-off-by: Michal Simek <michal.simek at xilinx.com>
---

Changes in v2:
- rename  nextrxbuffertouse to use_rx_pong_buffer_next - Joe
- fix type in immediatelly - Joe
- Redesign packet lenght size to two subsequent reads

 drivers/net/xilinx_emaclite.c | 125 ++++++++++++++++++++++++------------------
 1 file changed, 73 insertions(+), 52 deletions(-)

diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index e97ce2ce31f3..800345bba489 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -17,15 +17,12 @@
 #include <miiphy.h>
 #include <fdtdec.h>
 #include <asm-generic/errno.h>
+#include <linux/kernel.h>
 
 #undef DEBUG
 
 #define ENET_ADDR_LENGTH	6
-
-/* EmacLite constants */
-#define XEL_BUFFER_OFFSET	0x0800	/* Next buffer's offset */
-#define XEL_RSR_OFFSET		0x17FC	/* Rx status */
-#define XEL_RXBUFF_OFFSET	0x1000	/* Receive Buffer */
+#define ETH_FCS_LEN		4 /* Octets in the FCS */
 
 /* Xmit complete */
 #define XEL_TSR_XMIT_BUSY_MASK		0x00000001UL
@@ -86,7 +83,7 @@ struct emaclite_regs {
 };
 
 struct xemaclite {
-	u32 nextrxbuffertouse;	/* Next RX buffer to read from */
+	bool use_rx_pong_buffer_next;	/* Next RX buffer to read from */
 	u32 txpp;		/* TX ping pong buffer */
 	u32 rxpp;		/* RX ping pong buffer */
 	int phyaddr;
@@ -453,63 +450,87 @@ static int emaclite_send(struct eth_device *dev, void *ptr, int len)
 
 static int emaclite_recv(struct eth_device *dev)
 {
-	u32 length;
-	u32 reg;
-	u32 baseaddress;
+	u32 length, first_read, reg, attempt = 0;
+	void *addr, *ack;
 	struct xemaclite *emaclite = dev->priv;
-
-	baseaddress = dev->iobase + emaclite->nextrxbuffertouse;
-	reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
-	debug("Testing data at address 0x%x\n", baseaddress);
-	if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
-		if (emaclite->rxpp)
-			emaclite->nextrxbuffertouse ^= XEL_BUFFER_OFFSET;
+	struct emaclite_regs *regs = emaclite->regs;
+	struct ethernet_hdr *eth;
+	struct ip_udp_hdr *ip;
+
+try_again:
+	if (!emaclite->use_rx_pong_buffer_next) {
+		reg = in_be32(&regs->rx_ping_rsr);
+		debug("Testing data at rx_ping\n");
+		if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
+			debug("Data found in rx_ping buffer\n");
+			addr = &regs->rx_ping;
+			ack = &regs->rx_ping_rsr;
+		} else {
+			debug("Data not found in rx_ping buffer\n");
+			/* Pong buffer is not available - return immediately */
+			if (!emaclite->rxpp)
+				return -1;
+
+			/* Try pong buffer if this is first attempt */
+			if (attempt++)
+				return -1;
+			emaclite->use_rx_pong_buffer_next =
+					!emaclite->use_rx_pong_buffer_next;
+			goto try_again;
+		}
 	} else {
-
-		if (!emaclite->rxpp) {
-			debug("No data was available - address 0x%x\n",
-								baseaddress);
-			return 0;
+		reg = in_be32(&regs->rx_pong_rsr);
+		debug("Testing data at rx_pong\n");
+		if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
+			debug("Data found in rx_pong buffer\n");
+			addr = &regs->rx_pong;
+			ack = &regs->rx_pong_rsr;
 		} else {
-			baseaddress ^= XEL_BUFFER_OFFSET;
-			reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
-			if ((reg & XEL_RSR_RECV_DONE_MASK) !=
-						XEL_RSR_RECV_DONE_MASK) {
-				debug("No data was available - address 0x%x\n",
-						baseaddress);
-				return 0;
-			}
+			debug("Data not found in rx_pong buffer\n");
+			/* Try ping buffer if this is first attempt */
+			if (attempt++)
+				return -1;
+			emaclite->use_rx_pong_buffer_next =
+					!emaclite->use_rx_pong_buffer_next;
+			goto try_again;
 		}
 	}
-	/* Get the length of the frame that arrived */
-	switch(((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0xC))) &
-			0xFFFF0000 ) >> 16) {
-		case 0x806:
-			length = 42 + 20; /* FIXME size of ARP */
-			debug("ARP Packet\n");
-			break;
-		case 0x800:
-			length = 14 + 14 +
-			(((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET +
-						0x10))) & 0xFFFF0000) >> 16);
-			/* FIXME size of IP packet */
-			debug ("IP Packet\n");
-			break;
-		default:
-			debug("Other Packet\n");
-			length = PKTSIZE;
-			break;
+
+	/* Read all bytes for ARP packet with 32bit alignment - 48bytes  */
+	first_read = ALIGN(ETHER_HDR_SIZE + ARP_HDR_SIZE + ETH_FCS_LEN, 4);
+	xemaclite_alignedread(addr, etherrxbuff, first_read);
+
+	/* Detect real packet size */
+	eth = (struct ethernet_hdr *)etherrxbuff;
+	switch (ntohs(eth->et_protlen)) {
+	case PROT_ARP:
+		length = first_read;
+		debug("ARP Packet %x\n", length);
+		break;
+	case PROT_IP:
+		ip = (struct ip_udp_hdr *)(etherrxbuff + ETHER_HDR_SIZE);
+		length = ntohs(ip->ip_len);
+		length += ETHER_HDR_SIZE + ETH_FCS_LEN;
+		debug("IP Packet %x\n", length);
+		break;
+	default:
+		debug("Other Packet\n");
+		length = PKTSIZE;
+		break;
 	}
 
-	xemaclite_alignedread((u32 *) (baseaddress + XEL_RXBUFF_OFFSET),
-			etherrxbuff, length);
+	/* Read the rest of the packet which is longer then first read */
+	if (length != first_read)
+		xemaclite_alignedread(addr + first_read,
+				      etherrxbuff + first_read,
+				      length - first_read);
 
 	/* Acknowledge the frame */
-	reg = in_be32 (baseaddress + XEL_RSR_OFFSET);
+	reg = in_be32(ack);
 	reg &= ~XEL_RSR_RECV_DONE_MASK;
-	out_be32 (baseaddress + XEL_RSR_OFFSET, reg);
+	out_be32(ack, reg);
 
-	debug("Packet receive from 0x%x, length %dB\n", baseaddress, length);
+	debug("Packet receive from 0x%p, length %dB\n", addr, length);
 	net_process_received_packet((uchar *)etherrxbuff, length);
 	return length;
 
-- 
1.9.1



More information about the U-Boot mailing list