Commit 4d2749be authored by Michal Simek's avatar Michal Simek

net: emaclite: Use indirect access in emaclite_recv

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: default avatarMichal Simek <michal.simek@xilinx.com>
parent 00702518
...@@ -17,15 +17,12 @@ ...@@ -17,15 +17,12 @@
#include <miiphy.h> #include <miiphy.h>
#include <fdtdec.h> #include <fdtdec.h>
#include <asm-generic/errno.h> #include <asm-generic/errno.h>
#include <linux/kernel.h>
#undef DEBUG #undef DEBUG
#define ENET_ADDR_LENGTH 6 #define ENET_ADDR_LENGTH 6
#define ETH_FCS_LEN 4 /* Octets in the FCS */
/* 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 */
/* Xmit complete */ /* Xmit complete */
#define XEL_TSR_XMIT_BUSY_MASK 0x00000001UL #define XEL_TSR_XMIT_BUSY_MASK 0x00000001UL
...@@ -86,7 +83,7 @@ struct emaclite_regs { ...@@ -86,7 +83,7 @@ struct emaclite_regs {
}; };
struct xemaclite { 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 txpp; /* TX ping pong buffer */
u32 rxpp; /* RX ping pong buffer */ u32 rxpp; /* RX ping pong buffer */
int phyaddr; int phyaddr;
...@@ -453,63 +450,87 @@ static int emaclite_send(struct eth_device *dev, void *ptr, int len) ...@@ -453,63 +450,87 @@ static int emaclite_send(struct eth_device *dev, void *ptr, int len)
static int emaclite_recv(struct eth_device *dev) static int emaclite_recv(struct eth_device *dev)
{ {
u32 length; u32 length, first_read, reg, attempt = 0;
u32 reg; void *addr, *ack;
u32 baseaddress;
struct xemaclite *emaclite = dev->priv; struct xemaclite *emaclite = dev->priv;
struct emaclite_regs *regs = emaclite->regs;
baseaddress = dev->iobase + emaclite->nextrxbuffertouse; struct ethernet_hdr *eth;
reg = in_be32 (baseaddress + XEL_RSR_OFFSET); struct ip_udp_hdr *ip;
debug("Testing data at address 0x%x\n", baseaddress);
if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { try_again:
if (emaclite->rxpp) if (!emaclite->use_rx_pong_buffer_next) {
emaclite->nextrxbuffertouse ^= XEL_BUFFER_OFFSET; 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 { } else {
reg = in_be32(&regs->rx_pong_rsr);
if (!emaclite->rxpp) { debug("Testing data at rx_pong\n");
debug("No data was available - address 0x%x\n", if ((reg & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
baseaddress); debug("Data found in rx_pong buffer\n");
return 0; addr = &regs->rx_pong;
ack = &regs->rx_pong_rsr;
} else { } else {
baseaddress ^= XEL_BUFFER_OFFSET; debug("Data not found in rx_pong buffer\n");
reg = in_be32 (baseaddress + XEL_RSR_OFFSET); /* Try ping buffer if this is first attempt */
if ((reg & XEL_RSR_RECV_DONE_MASK) != if (attempt++)
XEL_RSR_RECV_DONE_MASK) { return -1;
debug("No data was available - address 0x%x\n", emaclite->use_rx_pong_buffer_next =
baseaddress); !emaclite->use_rx_pong_buffer_next;
return 0; goto try_again;
}
} }
} }
/* Get the length of the frame that arrived */
switch(((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + 0xC))) & /* Read all bytes for ARP packet with 32bit alignment - 48bytes */
0xFFFF0000 ) >> 16) { first_read = ALIGN(ETHER_HDR_SIZE + ARP_HDR_SIZE + ETH_FCS_LEN, 4);
case 0x806: xemaclite_alignedread(addr, etherrxbuff, first_read);
length = 42 + 20; /* FIXME size of ARP */
debug("ARP Packet\n"); /* Detect real packet size */
break; eth = (struct ethernet_hdr *)etherrxbuff;
case 0x800: switch (ntohs(eth->et_protlen)) {
length = 14 + 14 + case PROT_ARP:
(((ntohl(in_be32 (baseaddress + XEL_RXBUFF_OFFSET + length = first_read;
0x10))) & 0xFFFF0000) >> 16); debug("ARP Packet %x\n", length);
/* FIXME size of IP packet */ break;
debug ("IP Packet\n"); case PROT_IP:
break; ip = (struct ip_udp_hdr *)(etherrxbuff + ETHER_HDR_SIZE);
default: length = ntohs(ip->ip_len);
debug("Other Packet\n"); length += ETHER_HDR_SIZE + ETH_FCS_LEN;
length = PKTSIZE; debug("IP Packet %x\n", length);
break; break;
default:
debug("Other Packet\n");
length = PKTSIZE;
break;
} }
xemaclite_alignedread((u32 *) (baseaddress + XEL_RXBUFF_OFFSET), /* Read the rest of the packet which is longer then first read */
etherrxbuff, length); if (length != first_read)
xemaclite_alignedread(addr + first_read,
etherrxbuff + first_read,
length - first_read);
/* Acknowledge the frame */ /* Acknowledge the frame */
reg = in_be32 (baseaddress + XEL_RSR_OFFSET); reg = in_be32(ack);
reg &= ~XEL_RSR_RECV_DONE_MASK; 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); net_process_received_packet((uchar *)etherrxbuff, length);
return length; return length;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment