lwip: Removed support for lltemac.

Removed all files related to lltemac support.

Signed-off-by: Anirudha Sarangi <anirudh@xilinx.com>
This commit is contained in:
Anirudha Sarangi 2015-02-09 17:11:47 +05:30 committed by Nava kishore Manne
parent 133715a74d
commit dc4df44a44
8 changed files with 0 additions and 2099 deletions

View file

@ -55,10 +55,6 @@
#include "netif/xemacliteif.h"
#endif
#ifdef XLWIP_CONFIG_INCLUDE_TEMAC
#include "netif/xlltemacif.h"
#endif
#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
#include "netif/xaxiemacif.h"
#endif
@ -149,20 +145,6 @@ xemac_add(struct netif *netif,
);
#else
return NULL;
#endif
case xemac_type_xps_ll_temac:
#ifdef XLWIP_CONFIG_INCLUDE_TEMAC
return netif_add(netif, ipaddr, netmask, gw,
(void*)mac_baseaddr,
xlltemacif_init,
#if NO_SYS
ethernet_input
#else
tcpip_input
#endif
);
#else
return NULL;
#endif
case xemac_type_axi_ethernet:
#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
@ -242,17 +224,6 @@ xemacif_input(struct netif *netif)
print("incorrect configuration: xps_ethernetlite drivers not present?");
while(1);
return 0;
#endif
case xemac_type_xps_ll_temac:
#ifdef XLWIP_CONFIG_INCLUDE_TEMAC
SYS_ARCH_PROTECT(lev);
n_packets = xlltemacif_input(netif);
SYS_ARCH_UNPROTECT(lev);
break;
#else
print("incorrect configuration: xps_ll_temac drivers not present?");
while(1);
return 0;
#endif
case xemac_type_axi_ethernet:
#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET

View file

@ -1,525 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
/*
* Copyright (c) 2007-2013 Xilinx, Inc. All rights reserved.
*
* Xilinx, Inc.
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include <stdio.h>
#include <string.h>
#include <xparameters.h>
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/igmp.h"
#include "netif/etharp.h"
#include "netif/xlltemacif.h"
#include "netif/xadapter.h"
#include "netif/xpqueue.h"
#include "xlltemacif_fifo.h"
#include "xlltemacif_hw.h"
#include "xparameters.h"
#include "xintc.h"
/* Define those to better describe your network interface. */
#define IFNAME0 't'
#define IFNAME1 'e'
#if LWIP_IGMP
static err_t xlltemacif_mac_filter_update (struct netif *netif, struct ip_addr *group,
u8_t action);
static u8_t xlltemac_mcast_entry_mask = 0;
#endif
/*
* this function is always called with interrupts off
* this function also assumes that there are available BD's
*/
static err_t
_unbuffered_low_level_output(xlltemacif_s *xlltemacif, struct pbuf *p)
{
XStatus status = 0;
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
if (XLlTemac_IsDma(&xlltemacif->lltemac))
status = lldma_sgsend(xlltemacif, p);
else
status = xllfifo_send(xlltemacif, p);
if (status != XST_SUCCESS) {
#if LINK_STATS
lwip_stats.link.drop++;
#endif
}
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
#if LINK_STATS
lwip_stats.link.xmit++;
#endif /* LINK_STATS */
return ERR_OK;
}
int
is_tx_space_available(xlltemacif_s *emac)
{
if (XLlTemac_IsDma(&emac->lltemac)) {
XLlDma_BdRing *txring = &XLlDma_GetTxRing(&emac->lldma);
/* tx space is available as long as there are valid BD's */
return XLlDma_BdRingGetFreeCnt(txring);
} else {
return ((XLlFifo_TxVacancy(&emac->llfifo) * 4) > XTE_MAX_FRAME_SIZE);
}
}
/*
* low_level_output():
*
* Should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
*/
static err_t
low_level_output(struct netif *netif, struct pbuf *p)
{
SYS_ARCH_DECL_PROTECT(lev);
err_t err;
struct xemac_s *xemac = (struct xemac_s *)(netif->state);
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
SYS_ARCH_PROTECT(lev);
/* check if space is available to send */
if (is_tx_space_available(xlltemacif)) {
_unbuffered_low_level_output(xlltemacif, p);
err = ERR_OK;
} else {
#if LINK_STATS
lwip_stats.link.drop++;
#endif
print("pack dropped, no space\r\n");
err = ERR_MEM;
}
SYS_ARCH_UNPROTECT(lev);
return err;
}
/*
* low_level_input():
*
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
*/
static struct pbuf *
low_level_input(struct netif *netif)
{
struct xemac_s *xemac = (struct xemac_s *)(netif->state);
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
struct pbuf *p;
/* see if there is data to process */
if (pq_qlength(xlltemacif->recv_q) == 0)
return NULL;
/* return one packet from receive q */
p = (struct pbuf *)pq_dequeue(xlltemacif->recv_q);
return p;
}
/*
* xlltemacif_output():
*
* This function is called by the TCP/IP stack when an IP packet
* should be sent. It calls the function called low_level_output() to
* do the actual transmission of the packet.
*
*/
static err_t
xlltemacif_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr)
{
/* resolve hardware address, then send (or queue) packet */
return etharp_output(netif, p, ipaddr);
}
/*
* xlltemacif_input():
*
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface.
*
* Returns the number of packets read (max 1 packet on success,
* 0 if there are no packets)
*
*/
int
xlltemacif_input(struct netif *netif)
{
struct eth_hdr *ethhdr;
struct pbuf *p;
SYS_ARCH_DECL_PROTECT(lev);
/* move received packet into a new pbuf */
SYS_ARCH_PROTECT(lev);
p = low_level_input(netif);
SYS_ARCH_UNPROTECT(lev);
/* no packet could be read, silently ignore this */
if (p == NULL)
return 0;
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_ARP:
#if PPPOE_SUPPORT
/* PPPoE packet? */
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, ("xlltemacif_input: IP input error\r\n"));
pbuf_free(p);
p = NULL;
}
break;
default:
pbuf_free(p);
p = NULL;
break;
}
return 1;
}
static err_t
low_level_init(struct netif *netif)
{
unsigned mac_address = (unsigned)(netif->state);
struct xemac_s *xemac;
xlltemacif_s *xlltemacif;
xlltemacif = mem_malloc(sizeof *xlltemacif);
if (xlltemacif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("xlltemacif_init: out of memory\r\n"));
return ERR_MEM;
}
xemac = mem_malloc(sizeof *xemac);
if (xemac == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("xlltemacif_init: out of memory\r\n"));
return ERR_MEM;
}
xemac->state = (void *)xlltemacif;
xemac->topology_index = xtopology_find_index(mac_address);
xemac->type = xemac_type_xps_ll_temac;
xlltemacif->send_q = NULL;
xlltemacif->recv_q = pq_create_queue();
if (!xlltemacif->recv_q)
return ERR_MEM;
/* maximum transfer unit */
#ifdef USE_JUMBO_FRAMES
netif->mtu = XTE_JUMBO_MTU - XTE_HDR_SIZE;
#else
netif->mtu = XTE_MTU - XTE_HDR_SIZE;
#endif
#if LWIP_IGMP
netif->igmp_mac_filter = xlltemacif_mac_filter_update;
#endif
/* broadcast capability */
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
#if LWIP_IGMP
netif->flags |= NETIF_FLAG_IGMP;
#endif
#if !NO_SYS
sys_sem_new(&xemac->sem_rx_data_available, 0);
#endif
/* initialize the mac */
init_lltemac(xlltemacif, netif);
/* figure out if the system has DMA */
if (XLlTemac_IsDma(&xlltemacif->lltemac)) {
/* initialize the DMA engine */
init_sdma(xemac);
} else if (XLlTemac_IsFifo(&xlltemacif->lltemac)) {
/* initialize the locallink FIFOs */
init_ll_fifo(xemac);
} else {
/* should not occur */
LWIP_DEBUGF(NETIF_DEBUG, ("xlltemacif_init: lltemac is not configured with DMA or FIFO\r\n"));
return ERR_IF;
}
/* replace the state in netif (currently the emac baseaddress)
* with the xlltemac instance pointer.
*/
netif->state = (void *)xemac;
return ERR_OK;
}
#if LWIP_IGMP
static err_t
xlltemacif_mac_filter_update (struct netif *netif, struct ip_addr *group,
u8_t action)
{
err_t return_val = ERR_OK;
u8_t multicast_mac_addr[6];
u8_t multicast_mac_addr_to_clr[6];
u8_t temp_mask;
int entry;
int i;
u8_t * ip_addr_temp = (u8_t *)group;
struct xemac_s *xemac = (struct xemac_s *)(netif->state);
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
if (action == IGMP_ADD_MAC_FILTER) {
if ((ip_addr_temp[0] >= 224) && (ip_addr_temp[0] <= 239)) {
if (xlltemac_mcast_entry_mask >= 0x0F) {
LWIP_DEBUGF(NETIF_DEBUG,
("xlltemacif_mac_filter_update: No multicast address registers left.\r\n"));
LWIP_DEBUGF(NETIF_DEBUG,
(" Multicast MAC address add operation failure !!\r\n"));
return_val = ERR_MEM;
} else {
for (i = 0; i < 4; i++) {
temp_mask = (0x01) << i;
if ((xlltemac_mcast_entry_mask &
temp_mask) == temp_mask) {
continue;
} else {
entry = i;
xlltemac_mcast_entry_mask |=
temp_mask;
multicast_mac_addr[0] = 0x01;
multicast_mac_addr[1] = 0x00;
multicast_mac_addr[2] = 0x5E;
multicast_mac_addr[3] =
ip_addr_temp[1] & 0x7F;
multicast_mac_addr[4] =
ip_addr_temp[2];
multicast_mac_addr[5] =
ip_addr_temp[3];
XLlTemac_Stop
(&xlltemacif->lltemac);
XLlTemac_MulticastAdd
(&xlltemacif->lltemac,
multicast_mac_addr,entry);
XLlTemac_Start
(&xlltemacif->lltemac);
LWIP_DEBUGF(NETIF_DEBUG,
("xlltemacif_mac_filter_update: Muticast MAC address successfully added.\r\n"));
return_val = ERR_OK;
break;
}
}
if (i == 4) {
LWIP_DEBUGF(NETIF_DEBUG,
("xlltemacif_mac_filter_update: No multicast address registers left.\r\n"));
LWIP_DEBUGF(NETIF_DEBUG,
(" Multicast MAC address add operation failure !!\r\n"));
return_val = ERR_MEM;
}
}
} else {
LWIP_DEBUGF(NETIF_DEBUG,
("xlltemacif_mac_filter_update: The requested MAC address is not a multicast address.\r\n"));
LWIP_DEBUGF(NETIF_DEBUG,
(" Multicast address add operation failure !!\r\n"));
return_val = ERR_ARG;
}
} else if (action == IGMP_DEL_MAC_FILTER) {
if ((ip_addr_temp[0] < 224) || (ip_addr_temp[0] > 239)) {
LWIP_DEBUGF(NETIF_DEBUG,
("xlltemacif_mac_filter_update: The requested MAC address is not a multicast address.\r\n"));
LWIP_DEBUGF(NETIF_DEBUG,
(" Multicast address add operation failure !!\r\n"));
return_val = ERR_ARG;
} else {
for (i = 0; i < 4; i++) {
temp_mask = (0x01) << i;
if ((xlltemac_mcast_entry_mask & temp_mask)
== temp_mask) {
XLlTemac_MulticastGet
(&xlltemacif->lltemac,
multicast_mac_addr_to_clr, i);
if ((ip_addr_temp[3] ==
multicast_mac_addr_to_clr[5]) &&
(ip_addr_temp[2] ==
multicast_mac_addr_to_clr[4]) &&
((ip_addr_temp[1] & 0x7f) ==
multicast_mac_addr_to_clr[3])) {
XLlTemac_Stop
(&xlltemacif->lltemac);
XLlTemac_MulticastClear
(&xlltemacif->lltemac, i);
XLlTemac_Start
(&xlltemacif->lltemac);
return_val = ERR_OK;
xlltemac_mcast_entry_mask
&= (~temp_mask);
break;
} else {
continue;
}
} else {
continue;
}
}
if (i == 4) {
LWIP_DEBUGF(NETIF_DEBUG,
("xlltemacif_mac_filter_update: No multicast address registers present with\r\n"));
LWIP_DEBUGF(NETIF_DEBUG,
(" the requested Multicast MAC address.\r\n"));
LWIP_DEBUGF(NETIF_DEBUG,
(" Multicast MAC address removal failure!!.\r\n"));
return_val = ERR_MEM;
}
}
}
return return_val;
}
#endif
/*
* xlltemacif_init():
*
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
*/
err_t
xlltemacif_init(struct netif *netif)
{
#if LWIP_SNMP
/* ifType ethernetCsmacd(6) @see RFC1213 */
netif->link_type = 6;
/* your link speed here */
netif->link_speed = ;
netif->ts = 0;
netif->ifinoctets = 0;
netif->ifinucastpkts = 0;
netif->ifinnucastpkts = 0;
netif->ifindiscards = 0;
netif->ifoutoctets = 0;
netif->ifoutucastpkts = 0;
netif->ifoutnucastpkts = 0;
netif->ifoutdiscards = 0;
#endif
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = xlltemacif_output;
netif->linkoutput = low_level_output;
low_level_init(netif);
#if 0
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif
return ERR_OK;
}

View file

@ -1,243 +0,0 @@
/******************************************************************************
*
* Copyright (C) 2007 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#include "lwipopts.h"
#if !NO_SYS
#include "xmk.h"
#include "sys/intr.h"
#include "lwip/sys.h"
#endif
#include "lwip/stats.h"
#include "netif/xadapter.h"
#include "netif/xlltemacif.h"
#include "xintc_l.h"
#include "xstatus.h"
#include "xlltemacif_fifo.h"
#include "xlwipconfig.h"
static void
xllfifo_recv_handler(struct xemac_s *xemac)
{
u32_t frame_length;
struct pbuf *p;
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
XLlFifo *llfifo = &xlltemacif->llfifo;
/* While there is data in the fifo ... */
while (XLlFifo_RxOccupancy(llfifo)) {
/* find packet length */
frame_length = XLlFifo_RxGetLen(llfifo);
/* allocate a pbuf */
p = pbuf_alloc(PBUF_RAW, frame_length, PBUF_POOL);
if (!p) {
char tmp_frame[XTE_MAX_FRAME_SIZE];
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
/* receive and drop packet to keep data & len registers in sync */
XLlFifo_Read(llfifo, tmp_frame, frame_length);
continue;
}
/* receive packet */
XLlFifo_Read(llfifo, p->payload, frame_length);
#if ETH_PAD_SIZE
len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
#endif
/* store it in the receive queue, where it'll be processed by xemacif input thread */
if (pq_enqueue(xlltemacif->recv_q, (void*)p) < 0) {
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
pbuf_free(p);
continue;
}
#if !NO_SYS
sys_sem_signal(&xemac->sem_rx_data_available);
#endif
#if LINK_STATS
lwip_stats.link.recv++;
#endif
}
}
static void
fifo_error_handler(xlltemacif_s *xlltemacif, u32_t pending_intr)
{
XLlFifo *llfifo = &xlltemacif->llfifo;
if (pending_intr & XLLF_INT_RPURE_MASK) {
print("llfifo: Rx under-read error");
}
if (pending_intr & XLLF_INT_RPORE_MASK) {
print("llfifo: Rx over-read error");
}
if (pending_intr & XLLF_INT_RPUE_MASK) {
print("llfifo: Rx fifo empty");
}
if (pending_intr & XLLF_INT_TPOE_MASK) {
print("llfifo: Tx fifo overrun");
}
if (pending_intr & XLLF_INT_TSE_MASK) {
print("llfifo: Tx length mismatch");
}
/* Reset the tx or rx side of the fifo as needed */
if (pending_intr & XLLF_INT_RXERROR_MASK) {
XLlFifo_IntClear(llfifo, XLLF_INT_RRC_MASK);
XLlFifo_RxReset(llfifo);
}
if (pending_intr & XLLF_INT_TXERROR_MASK) {
XLlFifo_IntClear(llfifo, XLLF_INT_TRC_MASK);
XLlFifo_TxReset(llfifo);
}
}
static void
xllfifo_intr_handler(struct xemac_s *xemac)
{
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
XLlFifo *llfifo = &xlltemacif->llfifo;
u32_t pending_fifo_intr = XLlFifo_IntPending(llfifo);
while (pending_fifo_intr) {
if (pending_fifo_intr & XLLF_INT_RC_MASK) {
/* receive interrupt */
XLlFifo_IntClear(llfifo, XLLF_INT_RC_MASK);
xllfifo_recv_handler(xemac);
} else if (pending_fifo_intr & XLLF_INT_TC_MASK) {
/* tx intr */
XLlFifo_IntClear(llfifo, XLLF_INT_TC_MASK);
} else {
XLlFifo_IntClear(llfifo, XLLF_INT_ALL_MASK &
~(XLLF_INT_RC_MASK |
XLLF_INT_TC_MASK));
fifo_error_handler(xlltemacif, pending_fifo_intr);
}
pending_fifo_intr = XLlFifo_IntPending(llfifo);
}
}
XStatus
init_ll_fifo(struct xemac_s *xemac)
{
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
#if NO_SYS
struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
#endif
/* initialize ll fifo */
XLlFifo_Initialize(&xlltemacif->llfifo,
XLlTemac_LlDevBaseAddress(&xlltemacif->lltemac));
/* Clear any pending FIFO interrupts */
XLlFifo_IntClear(&xlltemacif->llfifo, XLLF_INT_ALL_MASK);
/* enable fifo interrupts */
XLlFifo_IntEnable(&xlltemacif->llfifo, XLLF_INT_ALL_MASK);
#if NO_SYS
/* Register temac interrupt with interrupt controller */
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xlltemacif->lltemac.Config.TemacIntr,
(XInterruptHandler)xlltemac_error_handler,
&xlltemacif->lltemac);
/* connect & enable FIFO interrupt */
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xlltemacif->lltemac.Config.LLFifoIntr,
(XInterruptHandler)xllfifo_intr_handler,
xemac);
/* Enable EMAC interrupts in the interrupt controller */
do {
/* read current interrupt enable mask */
unsigned int cur_mask = XIntc_In32(xtopologyp->intc_baseaddr + XIN_IER_OFFSET);
/* form new mask enabling SDMA & ll_temac interrupts */
cur_mask = cur_mask
| (1 << xlltemacif->lltemac.Config.LLFifoIntr)
| (1 << xlltemacif->lltemac.Config.TemacIntr);
/* set new mask */
XIntc_EnableIntr(xtopologyp->intc_baseaddr, cur_mask);
} while (0);
#else
/* connect & enable TEMAC interrupts */
register_int_handler(xlltemacif->lltemac.Config.TemacIntr,
(XInterruptHandler)xlltemac_error_handler,
&xlltemacif->lltemac);
enable_interrupt(xlltemacif->lltemac.Config.TemacIntr);
/* connect & enable FIFO interrupts */
register_int_handler(xlltemacif->lltemac.Config.LLFifoIntr,
(XInterruptHandler)xllfifo_intr_handler,
xemac);
enable_interrupt(xlltemacif->lltemac.Config.LLFifoIntr);
#endif
return 0;
}
XStatus
xllfifo_send(xlltemacif_s *xlltemacif, struct pbuf *p)
{
XLlFifo *llfifo = &xlltemacif->llfifo;
u32_t l = 0;
struct pbuf *q;
for(q = p; q != NULL; q = q->next) {
/* write frame data to FIFO */
XLlFifo_Write(llfifo, q->payload, q->len);
l += q->len;
}
/* initiate transmit */
XLlFifo_TxSetLen(llfifo, l);
return 0;
}

View file

@ -1,19 +0,0 @@
#ifndef __XLLTEMACIF_FIFO_H_
#define __XLLTEMACIF_FIFO_H_
#include "xparameters.h"
#include "netif/xlltemacif.h"
#include "xlwipconfig.h"
#ifdef __cplusplus
extern "C" {
#endif
XStatus init_ll_fifo(struct xemac_s *xemac);
XStatus xllfifo_send(xlltemacif_s *xlltemacif, struct pbuf *p);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,133 +0,0 @@
/******************************************************************************
*
* Copyright (C) 2007 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#include "netif/xlltemacif.h"
#include "lwipopts.h"
static XLlTemac_Config *
xlltemac_lookup_config(unsigned mac_base)
{
extern XLlTemac_Config XLlTemac_ConfigTable[];
XLlTemac_Config *CfgPtr = NULL;
int i;
for (i = 0; i < XPAR_XLLTEMAC_NUM_INSTANCES; i++) {
if (XLlTemac_ConfigTable[i].BaseAddress == mac_base) {
CfgPtr = &XLlTemac_ConfigTable[i];
break;
}
}
return (CfgPtr);
}
void
init_lltemac(xlltemacif_s *xlltemacif, struct netif *netif)
{
int rdy;
unsigned mac_address = (unsigned)(netif->state);
unsigned link_speed = 1000;
unsigned options;
unsigned lock_message_printed = 0;
/* obtain config of this emac */
XLlTemac_Config *mac_config = xlltemac_lookup_config(mac_address);
XLlTemac *xlltemacp = &xlltemacif->lltemac;
XLlTemac_CfgInitialize(xlltemacp, mac_config, mac_config->BaseAddress);
options = XLlTemac_GetOptions(xlltemacp);
options |= XTE_FLOW_CONTROL_OPTION;
options |= XTE_JUMBO_OPTION;
options |= XTE_TRANSMITTER_ENABLE_OPTION;
options |= XTE_RECEIVER_ENABLE_OPTION;
options |= XTE_FCS_STRIP_OPTION;
options |= XTE_MULTICAST_OPTION;
XLlTemac_SetOptions(xlltemacp, options);
XLlTemac_ClearOptions(xlltemacp, ~options);
/* set mac address */
XLlTemac_SetMacAddress(xlltemacp, (Xuint8*)(netif->hwaddr));
/* make sure the hard TEMAC is ready */
rdy = XLlTemac_ReadReg(xlltemacp->Config.BaseAddress,
XTE_RDY_OFFSET);
while ((rdy & XTE_RDY_HARD_ACS_RDY_MASK) == 0) {
rdy = XLlTemac_ReadReg(xlltemacp->Config.BaseAddress,
XTE_RDY_OFFSET);
}
link_speed = Phy_Setup(xlltemacp);
XLlTemac_SetOperatingSpeed(xlltemacp, link_speed);
/* Setting the operating speed of the MAC needs a delay. */
{
volatile int wait;
for (wait=0; wait < 100000; wait++);
for (wait=0; wait < 100000; wait++);
}
/* in a soft temac implementation, we need to explicitly make sure that
* the RX DCM has been locked. See xps_ll_temac manual for details.
* This bit is guaranteed to be 1 for hard temac's
*/
lock_message_printed = 0;
while (!(XLlTemac_ReadReg(xlltemacp->Config.BaseAddress, XTE_IS_OFFSET)
& XTE_INT_RXDCM_LOCK_MASK)) {
int first = 1;
if (first) {
print("Waiting for RX DCM to lock..");
first = 0;
lock_message_printed = 1;
}
}
if (lock_message_printed)
print("RX DCM locked.\r\n");
/* start the temac */
XLlTemac_Start(xlltemacp);
/* enable TEMAC interrupts */
XLlTemac_IntEnable(xlltemacp, XTE_INT_RECV_ERROR_MASK);
}
void
xlltemac_error_handler(XLlTemac * Temac)
{
unsigned Pending = XLlTemac_IntPending(Temac);
if (Pending & XTE_INT_RXFIFOOVR_MASK) {
print("Temac error interrupt: Rx fifo over run\r\n");
}
XLlTemac_IntClear(Temac, Pending);
}

View file

@ -1,49 +0,0 @@
/******************************************************************************
*
* Copyright (C) 2007 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#ifndef __XLLTEMACIF_HW_H_
#define __XLLTEMACIF_HW_H_
#include "netif/xlltemacif.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
void init_lltemac(xlltemacif_s *xlltemacif, struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,311 +0,0 @@
/*
* Copyright (c) 2007-2008, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Advanced Micro Devices, Inc. nor the names
* of its contributors may be used to endorse or promote products
* derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Some portions copyright (c) 2008-2013 Xilinx, Inc. All rights reserved.
*
* Xilinx, Inc.
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" AS A
* COURTESY TO YOU. BY PROVIDING THIS DESIGN, CODE, OR INFORMATION AS
* ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, APPLICATION OR
* STANDARD, XILINX IS MAKING NO REPRESENTATION THAT THIS IMPLEMENTATION
* IS FREE FROM ANY CLAIMS OF INFRINGEMENT, AND YOU ARE RESPONSIBLE
* FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE FOR YOUR IMPLEMENTATION.
* XILINX EXPRESSLY DISCLAIMS ANY WARRANTY WHATSOEVER WITH RESPECT TO
* THE ADEQUACY OF THE IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO
* ANY WARRANTIES OR REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE
* FROM CLAIMS OF INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE.
*
*/
#include "netif/xlltemacif.h"
#include "lwipopts.h"
/* Advertisement control register. */
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
#define ADVERTISE_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | \
ADVERTISE_10HALF | ADVERTISE_100HALF)
#define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF)
#define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF)
#define ADVERTISE_1000 0x0300
#define IEEE_CONTROL_REG_OFFSET 0
#define IEEE_STATUS_REG_OFFSET 1
#define IEEE_AUTONEGO_ADVERTISE_REG 4
#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5
#define IEEE_PARTNER_ABILITIES_2_REG_OFFSET 8
#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10
#define IEEE_1000_ADVERTISE_REG_OFFSET 9
#define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040
#define IEEE_CTRL_LINKSPEED_MASK 0x0040
#define IEEE_CTRL_LINKSPEED_1000M 0x0040
#define IEEE_CTRL_LINKSPEED_100M 0x2000
#define IEEE_CTRL_LINKSPEED_10M 0x0000
#define IEEE_CTRL_RESET_MASK 0x8000
#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000
#define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008
#define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020
#define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200
#define IEEE_STAT_1GBPS_EXTENSIONS 0x0100
#define IEEE_AN1_ABILITY_MASK 0x1FE0
#define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00
#define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380
#define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060
#define PHY_DETECT_REG 1
#define PHY_DETECT_MASK 0x1808
static int detect_phy(XLlTemac *xlltemacp)
{
u16 phy_reg;
u32 phy_addr;
for (phy_addr = 31; phy_addr > 0; phy_addr--) {
XLlTemac_PhyRead(xlltemacp, phy_addr, PHY_DETECT_REG, &phy_reg);
if ((phy_reg != 0xFFFF) &&
((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
/* Found a valid PHY address */
LWIP_DEBUGF(NETIF_DEBUG, ("XLlTemac detect_phy: PHY detected at address %d.\r\n", phy_addr));
LWIP_DEBUGF(NETIF_DEBUG, ("XLlTemac detect_phy: PHY detected.\r\n"));
return phy_addr;
}
}
LWIP_DEBUGF(NETIF_DEBUG, ("XLlTemac detect_phy: No PHY detected. Assuming a PHY at address 0\r\n"));
/* default to zero */
return 0;
}
unsigned
get_IEEE_phy_speed(XLlTemac *xlltemacp)
{
u16 control;
u16 status;
u16 partner_capabilities;
u16 partner_capabilities_1000;
u16 phylinkspeed;
u32 phy_addr = detect_phy(xlltemacp);
XLlTemac_PhyWrite(xlltemacp, phy_addr,
IEEE_1000_ADVERTISE_REG_OFFSET,
ADVERTISE_1000);
XLlTemac_PhyWrite(xlltemacp, phy_addr,
IEEE_AUTONEGO_ADVERTISE_REG,
ADVERTISE_100_AND_10);
XLlTemac_PhyRead(xlltemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
&control);
control |= (IEEE_CTRL_AUTONEGOTIATE_ENABLE |
IEEE_STAT_AUTONEGOTIATE_RESTART);
XLlTemac_PhyWrite(xlltemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
control);
/* Read PHY control and status registers is successful. */
XLlTemac_PhyRead(xlltemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
&control);
XLlTemac_PhyRead(xlltemacp, phy_addr,
IEEE_STATUS_REG_OFFSET,
&status);
if ((control & IEEE_CTRL_AUTONEGOTIATE_ENABLE) &&
(status & IEEE_STAT_AUTONEGOTIATE_CAPABLE)) {
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
XLlTemac_PhyRead(xlltemacp, phy_addr,
IEEE_STATUS_REG_OFFSET,
&status);
}
XLlTemac_PhyRead(xlltemacp, phy_addr,
IEEE_PARTNER_ABILITIES_1_REG_OFFSET,
&partner_capabilities);
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
XLlTemac_PhyRead(xlltemacp, phy_addr,
IEEE_PARTNER_ABILITIES_3_REG_OFFSET,
&partner_capabilities_1000);
if (partner_capabilities_1000 &
IEEE_AN3_ABILITY_MASK_1GBPS)
return 1000;
}
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_100MBPS)
return 100;
if (partner_capabilities & IEEE_AN1_ABILITY_MASK_10MBPS)
return 10;
xil_printf("%s: unknown PHY link speed, setting TEMAC speed to be 10 Mbps\r\n",
__FUNCTION__);
return 10;
} else {
/* Update TEMAC speed accordingly */
if (status & IEEE_STAT_1GBPS_EXTENSIONS) {
/* Get commanded link speed */
phylinkspeed = control & IEEE_CTRL_1GBPS_LINKSPEED_MASK;
switch (phylinkspeed) {
case (IEEE_CTRL_LINKSPEED_1000M):
return 1000;
case (IEEE_CTRL_LINKSPEED_100M):
return 100;
case (IEEE_CTRL_LINKSPEED_10M):
return 10;
default:
xil_printf("%s: unknown PHY link speed (%d), setting TEMAC speed to be 10 Mbps\r\n",
__FUNCTION__, phylinkspeed);
return 10;
}
} else {
return (control & IEEE_CTRL_LINKSPEED_MASK) ? 100 : 10;
}
}
}
unsigned configure_IEEE_phy_speed(XLlTemac *xlltemacp, unsigned speed)
{
u16 control;
u32 phy_addr = detect_phy(xlltemacp);
XLlTemac_PhyRead(xlltemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
&control);
control &= ~IEEE_CTRL_LINKSPEED_1000M;
control &= ~IEEE_CTRL_LINKSPEED_100M;
control &= ~IEEE_CTRL_LINKSPEED_10M;
if (speed == 1000) {
control |= IEEE_CTRL_LINKSPEED_1000M;
}
else if (speed == 100) {
control |= IEEE_CTRL_LINKSPEED_100M;
/* Dont advertise PHY speed of 1000 Mbps */
XLlTemac_PhyWrite(xlltemacp, phy_addr,
IEEE_1000_ADVERTISE_REG_OFFSET,
0);
/* Dont advertise PHY speed of 10 Mbps */
XLlTemac_PhyWrite(xlltemacp, phy_addr,
IEEE_AUTONEGO_ADVERTISE_REG,
ADVERTISE_100);
}
else if (speed == 10) {
control |= IEEE_CTRL_LINKSPEED_10M;
/* Dont advertise PHY speed of 1000 Mbps */
XLlTemac_PhyWrite(xlltemacp, phy_addr,
IEEE_1000_ADVERTISE_REG_OFFSET,
0);
/* Dont advertise PHY speed of 100 Mbps */
XLlTemac_PhyWrite(xlltemacp, phy_addr,
IEEE_AUTONEGO_ADVERTISE_REG,
ADVERTISE_10);
}
XLlTemac_PhyWrite(xlltemacp, phy_addr,
IEEE_CONTROL_REG_OFFSET,
control | IEEE_CTRL_RESET_MASK);
{
volatile int wait;
for (wait=0; wait < 100000; wait++);
for (wait=0; wait < 100000; wait++);
}
return 0;
}
unsigned Phy_Setup (XLlTemac *xlltemacp)
{
unsigned link_speed = 1000;
if (XLlTemac_GetPhysicalInterface(xlltemacp) ==
XTE_PHY_TYPE_RGMII_1_3) {
; /* Add PHY initialization code for RGMII 1.3 */
} else if (XLlTemac_GetPhysicalInterface(xlltemacp) ==
XTE_PHY_TYPE_RGMII_2_0) {
; /* Add PHY initialization code for RGMII 2.0 */
} else if (XLlTemac_GetPhysicalInterface(xlltemacp) ==
XTE_PHY_TYPE_SGMII) {
; /* Add PHY initialization code for SGMII */
} else if (XLlTemac_GetPhysicalInterface(xlltemacp) ==
XTE_PHY_TYPE_1000BASE_X) {
; /* Add PHY initialization code for 1000 Base-X */
}
/* set PHY <--> MAC data clock */
#ifdef CONFIG_LINKSPEED_AUTODETECT
link_speed = get_IEEE_phy_speed(xlltemacp);
xil_printf("auto-negotiated link speed: %d\r\n", link_speed);
#elif defined(CONFIG_LINKSPEED1000)
link_speed = 1000;
configure_IEEE_phy_speed(xlltemacp, link_speed);
xil_printf("link speed: %d\r\n", link_speed);
#elif defined(CONFIG_LINKSPEED100)
link_speed = 100;
configure_IEEE_phy_speed(xlltemacp, link_speed);
xil_printf("link speed: %d\r\n", link_speed);
#elif defined(CONFIG_LINKSPEED10)
link_speed = 10;
configure_IEEE_phy_speed(xlltemacp, link_speed);
xil_printf("link speed: %d\r\n", link_speed);
#endif
return link_speed;
}

View file

@ -1,790 +0,0 @@
/******************************************************************************
*
* Copyright (C) 2007 - 2014 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
#include "lwipopts.h"
#if !NO_SYS
#include "xmk.h"
#include "sys/intr.h"
#include "lwip/sys.h"
#endif
#include "lwip/stats.h"
#include "lwip/inet_chksum.h"
#include "netif/xadapter.h"
#include "netif/xlltemacif.h"
#include "xintc_l.h"
#include "xstatus.h"
#include "xlltemacif_fifo.h"
#include "xlwipconfig.h"
#include "xparameters.h"
#ifdef CONFIG_XTRACE
#include "xtrace.h"
#endif
/* Byte alignment of BDs */
#define BD_ALIGNMENT (XLLDMA_BD_MINIMUM_ALIGNMENT*2)
//#define USE_STATIC_BDSPACE
#ifdef USE_STATIC_BDSPACE
#define RXBD_SPACE_BYTES XLlDma_BdRingMemCalc(BD_ALIGNMENT, XLWIP_CONFIG_N_RX_DESC)
#define TXBD_SPACE_BYTES XLlDma_BdRingMemCalc(BD_ALIGNMENT, XLWIP_CONFIG_N_TX_DESC)
char rx_bdspace[RXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT)));
char tx_bdspace[TXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT)));
#endif
static unsigned sdma_debug = 0;
//#define SDMA_DEBUG
#ifdef SDMA_DEBUG
void print_packet(char *p, int n)
{
int i, j;
for (i = 0; i < n; i+=16) {
for (j = 0; j < 16; j++)
xil_printf("%02x ", *p++&0xff);
xil_printf("\r\n");
}
}
#endif
int
process_sent_bds(XLlDma_BdRing *txring)
{
XLlDma_Bd *txbdset, *txbd;
int n_bds, i;
XStatus Status;
/* obtain a list of processed BD's */
n_bds = XLlDma_BdRingFromHw(txring, XLLDMA_ALL_BDS, &txbdset);
if (n_bds == 0)
return -1;
/* free the pbuf associated with each BD */
for (i = 0, txbd = txbdset; i < n_bds; i++) {
struct pbuf *p = (struct pbuf *)XLlDma_BdGetId(txbd);
pbuf_free(p);
txbd = XLlDma_BdRingNext(txring, txbd);
}
/* free the processed BD's */
Status = XLlDma_BdRingFree(txring, n_bds, txbdset);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
return 0;
}
void
lldma_send_handler(void *arg)
{
unsigned irq_status;
struct xemac_s *xemac = (struct xemac_s *)(arg);
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
XLlDma_BdRing *TxRingPtr = &XLlDma_GetTxRing(&xlltemacif->lldma);
struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
XLlTemac *xlltemac = &xlltemacif->lltemac;
/* Read pending interrupts */
irq_status = XLlDma_BdRingGetIrq(TxRingPtr);
/* Acknowledge pending interrupts */
XLlDma_BdRingAckIrq(TxRingPtr, irq_status);
XIntc_AckIntr(xtopologyp->intc_baseaddr, 1 << xlltemac->Config.LLDmaTxIntr);
/*
* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((irq_status & XLLDMA_IRQ_ALL_ERR_MASK)) {
LWIP_DEBUGF(NETIF_DEBUG, ("%s: Error: irq_status & XLLDMA_IRQ_ALL_ERR_MASK", __FUNCTION__));
LWIP_DEBUGF(NETIF_DEBUG, ("lldma error interrupt is asserted\r\n"));
XLlDma_Reset(&xlltemacif->lldma);
return;
}
/* If Transmit done interrupt is asserted, process completed BD's */
if ((irq_status & (XLLDMA_IRQ_DELAY_MASK | XLLDMA_IRQ_COALESCE_MASK))) {
process_sent_bds(TxRingPtr);
}
}
#if !CHECKSUM_GEN_TCP
static void
_bd_csum_enable(XLlDma_Bd *bd)
{
XLlDma_BdWrite((bd), XLLDMA_BD_STSCTRL_USR0_OFFSET,
(XLlDma_BdRead((bd), XLLDMA_BD_STSCTRL_USR0_OFFSET)
| 1));
}
static void
_bd_csum_disable(XLlDma_Bd *bd)
{
XLlDma_BdWrite((bd), XLLDMA_BD_STSCTRL_USR0_OFFSET,
(XLlDma_BdRead((bd), XLLDMA_BD_STSCTRL_USR0_OFFSET)
& ~1));
}
static void
_bd_csum_set(XLlDma_Bd *bd, u16_t tx_csbegin, u16_t tx_csinsert, u16_t tx_csinit)
{
u32_t app1;
_bd_csum_enable(bd);
/* write start offset and insert offset into BD */
app1 = ((u32_t)tx_csbegin << 16) | (u32_t) tx_csinsert;
XLlDma_BdWrite(bd, XLLDMA_BD_USR1_OFFSET, app1);
/* insert init value */
XLlDma_BdWrite(bd, XLLDMA_BD_USR2_OFFSET, tx_csinit);
}
#endif
XStatus
lldma_sgsend(xlltemacif_s *xlltemacif, struct pbuf *p)
{
struct pbuf *q;
int n_pbufs;
XLlDma_Bd *txbdset, *txbd, *last_txbd = NULL;
XStatus Status;
XLlDma_BdRing *txring;
unsigned max_frame_size;
#ifdef USE_JUMBO_FRAMES
max_frame_size = XTE_MAX_JUMBO_FRAME_SIZE - 18;
#else
max_frame_size = XTE_MAX_FRAME_SIZE - 18;
#endif
txring = &XLlDma_GetTxRing(&xlltemacif->lldma);
/* first count the number of pbufs */
for (q = p, n_pbufs = 0; q != NULL; q = q->next)
n_pbufs++;
/* obtain as many BD's */
Status = XLlDma_BdRingAlloc(txring, n_pbufs, &txbdset);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error allocating RxBD"));
return ERR_IF;
}
for(q = p, txbd = txbdset; q != NULL; q = q->next) {
/* Send the data from the pbuf to the interface, one pbuf at a
time. The size of the data in each pbuf is kept in the ->len
variable. */
XLlDma_BdSetBufAddr(txbd, q->payload);
if (q->len > max_frame_size)
XLlDma_BdSetLength(txbd, max_frame_size);
else
XLlDma_BdSetLength(txbd, q->len);
XLlDma_BdSetId(txbd, (void *)q);
XLlDma_BdSetStsCtrl(txbd, 0);
XCACHE_FLUSH_DCACHE_RANGE(q->payload, q->len);
#ifdef SDMA_DEBUG
if (sdma_debug) {
LWIP_DEBUGF(NETIF_DEBUG, ("sending packet:\r\n"));
print_packet(q->payload, 60);
}
#endif
pbuf_ref(q);
last_txbd = txbd;
txbd = XLlDma_BdRingNext(txring, txbd);
}
if (n_pbufs == 1) {
XLlDma_BdSetStsCtrl(txbdset, XLLDMA_BD_STSCTRL_SOP_MASK
| XLLDMA_BD_STSCTRL_EOP_MASK);
} else {
/* in the first packet, set the SOP */
XLlDma_BdSetStsCtrl(txbdset, XLLDMA_BD_STSCTRL_SOP_MASK);
/* in the last packet, set the EOP */
XLlDma_BdSetStsCtrl(last_txbd, XLLDMA_BD_STSCTRL_EOP_MASK);
}
#if !CHECKSUM_GEN_TCP
_bd_csum_disable(txbdset);
/* offload TCP checksum calculation to hardware */
if (XLlTemac_IsTxCsum(&xlltemacif->lltemac)) {
if (p->len > sizeof(struct ethip_hdr)) {
struct ethip_hdr *ehdr = p->payload;
u8_t proto = IPH_PROTO(&ehdr->ip);
/* check if it is a TCP packet */
if (ehdr->eth.type == ETHTYPE_IP && proto == IP_PROTO_TCP) {
u32_t iphdr_len, csum_insert_offset;
u16_t tcp_len; /* TCP header length + data length in bytes */
u16_t csum_init = 0;
u16_t tcp_payload_offset;
/* determine length of IP header */
iphdr_len = (IPH_HL(&ehdr->ip) * 4);
tcp_payload_offset = XTE_HDR_SIZE + iphdr_len;
tcp_len = p->tot_len - tcp_payload_offset;
/* insert checksum at offset 16 for TCP, 6 for UDP */
if (proto == IP_PROTO_TCP)
csum_insert_offset = tcp_payload_offset + 16;
else if (proto == IP_PROTO_UDP)
csum_insert_offset = tcp_payload_offset + 6;
else
csum_insert_offset = 0;
/* compute pseudo header checksum value */
csum_init = inet_chksum_pseudo(NULL,
(ip_addr_t *)&ehdr->ip.src, (ip_addr_t *)&ehdr->ip.dest,
proto, tcp_len);
/* init buffer descriptor */
_bd_csum_set(txbdset, tcp_payload_offset, csum_insert_offset, ~csum_init);
}
}
}
#endif
/* enq to h/w */
return XLlDma_BdRingToHw(txring, n_pbufs, txbdset);
}
void
_setup_rx_bds(XLlDma_BdRing *rxring)
{
XLlDma_Bd *rxbd;
int n_bds, i;
XStatus Status;
struct pbuf *p;
n_bds = XLlDma_BdRingGetFreeCnt(rxring);
if (n_bds == 0)
return;
for (i = 0; i < n_bds; i++) {
Status = XLlDma_BdRingAlloc(rxring, 1, &rxbd);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error allocating RxBD"));
return;
}
#ifdef USE_JUMBO_FRAMES
p = pbuf_alloc(PBUF_RAW, XTE_MAX_JUMBO_FRAME_SIZE, PBUF_POOL);
#else
p = pbuf_alloc(PBUF_RAW, XTE_MAX_FRAME_SIZE, PBUF_POOL);
#endif
if (!p) {
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
LWIP_DEBUGF(NETIF_DEBUG, ("unable to alloc pbuf in recv_handler\r\n"));
#ifdef LWIP_STATS
if (sdma_debug) {
stats_display();
while (1)
;
}
#endif
return;
}
/*
* Setup the BD. The BD template used in the call to XLlTemac_SgSetSpace()
* set the "last" field of all RxBDs. Therefore we are not required to
* issue a XLlDma_Bd_SetLast(rxbd) here.
*/
XLlDma_BdSetBufAddr(rxbd, p->payload);
XLlDma_BdSetLength(rxbd, p->len);
XLlDma_BdSetStsCtrl(rxbd, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK);
XLlDma_BdSetId(rxbd, p);
XCACHE_FLUSH_DCACHE_RANGE(p, sizeof *p);
XCACHE_FLUSH_DCACHE_RANGE(rxbd, sizeof *rxbd);
/* Enqueue to HW */
Status = XLlDma_BdRingToHw(rxring, 1, rxbd);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error committing RxBD to hardware: "));
if (Status == XST_DMA_SG_LIST_ERROR)
LWIP_DEBUGF(NETIF_DEBUG, ("XST_DMA_SG_LIST_ERROR: this function was called out of sequence with XLlDma_BdRingAlloc()\r\n"));
else
LWIP_DEBUGF(NETIF_DEBUG, ("set of BDs was rejected because the first BD did not have its start-of-packet bit set, or the last BD did not have its end-of-packet bit set, or any one of the BD set has 0 as length value\r\n"));
return;
}
}
}
/*
* zero out the checksum field of this packet
*/
void
zero_checksum_field(struct pbuf *p)
{
/* the way checksum works in this implementation of lwIP is as follows:
- if checksum offload is disabled, then lwIP stack performs all checksum calculations
- if checksum is enabled,
- if computed csum says packet is valid, then we zero out the checksum field
- if computed csum says packet is invalid, we leave checksum as is
- upper layer recomputes checksum if it finds a non-zero checksum value
*/
struct ethip_hdr *ehdr = p->payload;
u32_t iphdr_len;
u16_t tcp_payload_offset;
u8_t proto = IPH_PROTO(&ehdr->ip);
iphdr_len = (IPH_HL(&ehdr->ip) * 4);
tcp_payload_offset = XTE_HDR_SIZE + iphdr_len;
if (ehdr->eth.type == ETHTYPE_IP && proto == IP_PROTO_TCP) {
/* set checksum = 0 */
*(u16_t*)(p->payload + tcp_payload_offset + 16) = 0;
}
}
u32_t
csum_sub(u32_t csum, u16_t v)
{
csum += (u32_t)v;
return csum + (csum < (u32_t)v);
}
static u16_t
extract_packet_len(XLlDma_Bd *rxbd) {
u16_t packet_len = XLlDma_BdRead(rxbd, XLLDMA_BD_USR4_OFFSET) & 0x3fff;
return packet_len;
}
static u16_t
extract_csum(XLlDma_Bd *rxbd) {
u16_t csum = XLlDma_BdRead(rxbd, XLLDMA_BD_USR3_OFFSET) & 0xffff;
return csum;
}
/*
* compare if the h/w computed checksum (stored in the rxbd)
* equals the TCP checksum value in the packet
*/
int
is_checksum_valid(XLlDma_Bd *rxbd, struct pbuf *p) {
struct ethip_hdr *ehdr = p->payload;
u8_t proto = IPH_PROTO(&ehdr->ip);
/* check if it is a TCP packet */
if (ehdr->eth.type == ETHTYPE_IP && proto == IP_PROTO_TCP) {
u32_t iphdr_len;
u16_t csum_in_packet, csum_in_rxbd, pseudo_csum, iphdr_csum, padding_csum;
u16_t tcp_payload_offset;
u32_t computed_csum;
u16_t padding_len, tcp_payload_len, packet_len;
u16_t csum;
/* determine length of IP header */
iphdr_len = (IPH_HL(&ehdr->ip) * 4);
tcp_payload_offset = XTE_HDR_SIZE + iphdr_len;
tcp_payload_len = IPH_LEN(&ehdr->ip) - IPH_HL(&ehdr->ip) * 4;
packet_len = extract_packet_len(rxbd);
padding_len = packet_len - tcp_payload_offset - tcp_payload_len;
csum_in_packet = *(u16_t*)(p->payload + tcp_payload_offset + 16);
csum_in_rxbd = extract_csum(rxbd);
pseudo_csum = inet_chksum_pseudo(NULL,
(ip_addr_t *)&ehdr->ip.src, (ip_addr_t *)&ehdr->ip.dest,
proto, tcp_payload_len);
/* xps_ll_temac computes the checksum of the packet starting at byte 14
* we need to subtract the values of the ethernet & IP headers
*/
iphdr_csum = inet_chksum(p->payload + 14, tcp_payload_offset - 14);
/* compute csum of padding bytes, if any */
padding_csum = inet_chksum(p->payload + p->tot_len - padding_len,
padding_len);
/* get the h/w checksum value */
computed_csum = (u32_t)csum_in_rxbd;
/* remove the effect of csumming the iphdr */
computed_csum = csum_sub(computed_csum, ~iphdr_csum);
/* add in the pseudo csum */
computed_csum = csum_sub(computed_csum, ~pseudo_csum);
/* remove any padding effect */
computed_csum = csum_sub(computed_csum, ~padding_csum);
/* normalize computed csum */
while (computed_csum >> 16) {
computed_csum = (computed_csum & 0xffff) + (computed_csum >> 16);
}
/* convert to 16 bits and take 1's complement */
csum = (u16_t)computed_csum;
csum = ~csum;
/* chksum is valid if: computed csum over the packet is 0 */
return !csum;
} else {
/* just say yes to all other packets */
/* the upper layers in the stack will compute and verify the checksum */
return 1;
}
}
void
lldma_recv_handler(void *arg)
{
struct pbuf *p;
unsigned irq_status, i;
XLlDma_Bd *rxbd, *rxbdset;
struct xemac_s *xemac = (struct xemac_s *)(arg);
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
XLlDma_BdRing *rxring = &XLlDma_GetRxRing(&xlltemacif->lldma);
struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
XLlTemac *xlltemac = &xlltemacif->lltemac;
XIntc_AckIntr(xtopologyp->intc_baseaddr, 1 << xlltemac->Config.LLDmaRxIntr);
XLlDma_BdRingIntDisable(rxring, XLLDMA_CR_IRQ_ALL_EN_MASK);
/* Read pending interrupts */
irq_status = XLlDma_BdRingGetIrq(rxring);
/* Acknowledge pending interrupts */
XLlDma_BdRingAckIrq(rxring, irq_status);
/* If error interrupt is asserted, raise error flag, reset the
* hardware to recover from the error, and return with no further
* processing.
*/
if ((irq_status & XLLDMA_IRQ_ALL_ERR_MASK)) {
LWIP_DEBUGF(NETIF_DEBUG, ("LlDma: Error: irq_status & XLLDMA_IRQ_ALL_ERR_MASK"));
XLlDma_Reset(&xlltemacif->lldma);
return;
}
/*
* If Reception done interrupt is asserted, call RX call back function
* to handle the processed BDs and then raise the according flag.
*/
if ((irq_status & (XLLDMA_IRQ_DELAY_MASK | XLLDMA_IRQ_COALESCE_MASK))) {
int bd_processed;
bd_processed = XLlDma_BdRingFromHw(rxring, XLLDMA_ALL_BDS, &rxbdset);
for (i = 0, rxbd = rxbdset; i < bd_processed; i++) {
p = (struct pbuf *)XLlDma_BdGetId(rxbd);
#ifdef USE_JUMBO_FRAMES
XCACHE_INVALIDATE_DCACHE_RANGE(p->payload, XTE_MAX_JUMBO_FRAME_SIZE);
#else
XCACHE_INVALIDATE_DCACHE_RANGE(p->payload, XTE_MAX_FRAME_SIZE);
#endif
#if !CHECKSUM_CHECK_TCP
/* compare RX checksum to TCP checksum value */
if (is_checksum_valid(rxbd, p)) {
/* if checksum is correct, then we re-write
* checksum field with 0's so the upper layer doesn't recompute
*/
zero_checksum_field(p);
}
#endif
#ifdef SDMA_DEBUG
if (sdma_debug)
print_packet(p->payload, 60);
#endif
/* store it in the receive queue,
* where it'll be processed by a different handler
*/
if (pq_enqueue(xlltemacif->recv_q, (void*)p) < 0) {
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
pbuf_free(p);
} else {
#if !NO_SYS
sys_sem_signal(&xemac->sem_rx_data_available);
#endif
}
rxbd = XLlDma_BdRingNext(rxring, rxbd);
}
/* free up the BD's */
XLlDma_BdRingFree(rxring, bd_processed, rxbdset);
/* return all the processed bd's back to the stack */
/* _setup_rx_bds -> use XLlDma_BdRingGetFreeCnt */
_setup_rx_bds(rxring);
}
XLlDma_BdRingIntEnable(rxring, XLLDMA_CR_IRQ_ALL_EN_MASK);
}
void *
alloc_bdspace(int n_desc)
{
int space = XLlDma_BdRingMemCalc(BD_ALIGNMENT, n_desc);
int padding = BD_ALIGNMENT*2;
void *unaligned_mem = mem_malloc(space + padding*4);
void *aligned_mem = (void *)(((unsigned)(unaligned_mem + BD_ALIGNMENT)) & ~(BD_ALIGNMENT - 1));
#ifdef SDMA_DEBUG
xil_printf("unaligned_mem start: %8x, end: %8x\r\n", unaligned_mem, unaligned_mem + space + padding * 4);
xil_printf(" aligned_mem start: %8x, end: %8x\r\n", aligned_mem, aligned_mem + space);
#endif
#if DEBUG
assert(aligned_mem > unaligned_mem);
assert(aligned_mem + space < unaligned_mem + space + padding);
#endif
return aligned_mem;
}
XStatus
init_sdma(struct xemac_s *xemac)
{
XLlDma_Bd BdTemplate;
XLlDma_BdRing *RxRingPtr, *TxRingPtr;
XLlDma_Bd *rxbd;
struct pbuf *p;
XStatus Status;
int i;
xlltemacif_s *xlltemacif = (xlltemacif_s *)(xemac->state);
#if NO_SYS
struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
#endif
/* initialize DMA */
XLlDma_Initialize(&xlltemacif->lldma, xlltemacif->lltemac.Config.LLDevBaseAddress);
RxRingPtr = &XLlDma_GetRxRing(&xlltemacif->lldma);
TxRingPtr = &XLlDma_GetTxRing(&xlltemacif->lldma);
xlltemacif->rx_bdspace = alloc_bdspace(XLWIP_CONFIG_N_RX_DESC);
xlltemacif->tx_bdspace = alloc_bdspace(XLWIP_CONFIG_N_TX_DESC);
if (!xlltemacif->rx_bdspace || !xlltemacif->tx_bdspace) {
xil_printf("%s@%d: Error: Unable to allocate memory for RX buffer descriptors",
__FILE__, __LINE__);
return XST_FAILURE;
}
/*
* Setup RxBD space.
*
* Setup a BD template for the Rx channel. This template will be copied to
* every RxBD. We will not have to explicitly set these again.
*/
XLlDma_BdClear(&BdTemplate);
/*
* Create the RxBD ring
*/
#ifdef USE_STATIC_BDSPACE
Status = XLlDma_BdRingCreate(RxRingPtr, (u32) &rx_bdspace,
(u32) &rx_bdspace, BD_ALIGNMENT,
XLWIP_CONFIG_N_RX_DESC);
#else
Status = XLlDma_BdRingCreate(RxRingPtr, (u32) xlltemacif->rx_bdspace,
(u32) xlltemacif->rx_bdspace, BD_ALIGNMENT,
XLWIP_CONFIG_N_RX_DESC);
#endif
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error setting up RxBD space"));
return XST_FAILURE;
}
Status = XLlDma_BdRingClone(RxRingPtr, &BdTemplate);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error initializing RxBD space"));
return XST_FAILURE;
}
/*
* Create the TxBD ring
*/
#ifdef USE_STATIC_BDSPACE
Status = XLlDma_BdRingCreate(TxRingPtr, (u32) &tx_bdspace,
(u32) &tx_bdspace, BD_ALIGNMENT,
XLWIP_CONFIG_N_TX_DESC);
#else
Status = XLlDma_BdRingCreate(TxRingPtr, (u32) xlltemacif->tx_bdspace,
(u32) xlltemacif->tx_bdspace, BD_ALIGNMENT,
XLWIP_CONFIG_N_TX_DESC);
#endif
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/* We reuse the bd template, as the same one will work for both rx and tx. */
Status = XLlDma_BdRingClone(TxRingPtr, &BdTemplate);
if (Status != XST_SUCCESS) {
return ERR_IF;
}
/* enable DMA interrupts */
XLlDma_BdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK);
XLlDma_BdRingIntEnable(RxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK);
/*
* Allocate 1 RxBD. Note that TEMAC utilizes an in-place allocation
* scheme. The returned rxbd will point to a free BD in the memory
* segment setup with the call to XLlTemac_SgSetSpace()
*/
for (i = 0; i < XLWIP_CONFIG_N_RX_DESC - 1; i++) {
Status = XLlDma_BdRingAlloc(RxRingPtr, 1, &rxbd);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error allocating RxBD"));
return ERR_IF;
}
#ifdef USE_JUMBO_FRAMES
p = pbuf_alloc(PBUF_RAW, XTE_MAX_JUMBO_FRAME_SIZE, PBUF_POOL);
#else
p = pbuf_alloc(PBUF_RAW, XTE_MAX_FRAME_SIZE, PBUF_POOL);
#endif
if (!p) {
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
LWIP_DEBUGF(NETIF_DEBUG, ("unable to alloc pbuf in recv_handler\r\n"));
return -1;
}
/*
* Setup the BD. The BD template used in the call to XLlTemac_SgSetSpace()
* set the "last" field of all RxBDs. Therefore we are not required to
* issue a XLlDma_Bd_SetLast(rxbd) here.
*/
XLlDma_BdSetBufAddr(rxbd, p->payload);
XLlDma_BdSetLength(rxbd, p->len);
XLlDma_BdSetStsCtrl(rxbd, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK);
XLlDma_BdSetId(rxbd, p);
XCACHE_FLUSH_DCACHE_RANGE(p, sizeof *p);
XCACHE_FLUSH_DCACHE_RANGE(rxbd, sizeof *rxbd);
/* Enqueue to HW */
Status = XLlDma_BdRingToHw(RxRingPtr, 1, rxbd);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error committing RxBD to HW"));
return XST_FAILURE;
}
}
/* start DMA */
Status = XLlDma_BdRingStart(TxRingPtr);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error failed to start TX BD ring"));
return XST_FAILURE;
}
Status = XLlDma_BdRingStart(RxRingPtr);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error failed to start RX BD ring"));
return XST_FAILURE;
}
Status = XLlDma_BdRingSetCoalesce(TxRingPtr, XLWIP_CONFIG_N_TX_COALESCE, 1);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error setting coalescing settings\r\n"));
return XST_FAILURE;
}
Status = XLlDma_BdRingSetCoalesce(RxRingPtr, XLWIP_CONFIG_N_RX_COALESCE, 1);
if (Status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error setting coalescing settings\r\n"));
return XST_FAILURE;
}
#if NO_SYS
/* Register temac interrupt with interrupt controller */
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xlltemacif->lltemac.Config.TemacIntr,
(XInterruptHandler)xlltemac_error_handler,
&xlltemacif->lltemac);
/* connect & enable DMA interrupts */
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xlltemacif->lltemac.Config.LLDmaTxIntr,
(XInterruptHandler)lldma_send_handler,
xemac);
XIntc_RegisterHandler(xtopologyp->intc_baseaddr,
xlltemacif->lltemac.Config.LLDmaRxIntr,
(XInterruptHandler)lldma_recv_handler,
xemac);
/* Enable EMAC interrupts in the interrupt controller */
do {
/* read current interrupt enable mask */
unsigned int cur_mask = XIntc_In32(xtopologyp->intc_baseaddr + XIN_IER_OFFSET);
/* form new mask enabling SDMA & ll_temac interrupts */
cur_mask = cur_mask
| (1 << xlltemacif->lltemac.Config.LLDmaTxIntr)
| (1 << xlltemacif->lltemac.Config.LLDmaRxIntr)
| (1 << xlltemacif->lltemac.Config.TemacIntr);
/* set new mask */
XIntc_EnableIntr(xtopologyp->intc_baseaddr, cur_mask);
} while (0);
#else
/* connect & enable TEMAC interrupts */
register_int_handler(xlltemacif->lltemac.Config.TemacIntr,
(XInterruptHandler)xlltemac_error_handler,
&xlltemacif->lltemac);
enable_interrupt(xlltemacif->lltemac.Config.TemacIntr);
/* connect & enable DMA interrupts */
register_int_handler(xlltemacif->lltemac.Config.LLDmaTxIntr,
(XInterruptHandler)lldma_send_handler,
xemac);
enable_interrupt(xlltemacif->lltemac.Config.LLDmaTxIntr);
register_int_handler(xlltemacif->lltemac.Config.LLDmaRxIntr,
(XInterruptHandler)lldma_recv_handler,
xemac);
enable_interrupt(xlltemacif->lltemac.Config.LLDmaRxIntr);
#endif
return 0;
}