lwip: Fix bugs in lwip
This patch fixes following issues: ---> PHY auto detection & PHY access issues. ---> The existing lwip seems to misbehave when it undergoes a stress or performance test with UDP packets. ---> Temac crashes and deadlocks if there is a high traffic load or transmitted packets are not successfully delivered to the other side. Signed-off-by: Kedareswara rao Appana <appanad@xilinx.com>
This commit is contained in:
parent
d4541c3d7a
commit
f45ada332c
8 changed files with 757 additions and 569 deletions
|
@ -1,5 +1,8 @@
|
|||
Change Log for lwip
|
||||
=================================
|
||||
2014-9-12
|
||||
* Created a new version lwip140_v2_4.
|
||||
* It has CR fixes for 827638, 830976, 828866.
|
||||
2014-12-11
|
||||
* Fixed the bug in the emaclite on zynq. Added the parameter
|
||||
use_emaclite_on_zynq to the mld file.
|
||||
|
|
|
@ -56,7 +56,7 @@ struct xemac_s {
|
|||
int topology_index;
|
||||
void *state;
|
||||
#if !NO_SYS
|
||||
sys_sem_t sem_rx_data_available;
|
||||
sys_sem_t sem_rx_data_available;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ extern "C" {
|
|||
#include "xlwipconfig.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "netif/etharp.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "netif/xadapter.h"
|
||||
|
||||
#include "xstatus.h"
|
||||
|
@ -63,10 +64,7 @@ extern "C" {
|
|||
void xemacpsif_setmac(u32_t index, u8_t *addr);
|
||||
u8_t* xemacpsif_getmac(u32_t index);
|
||||
err_t xemacpsif_init(struct netif *netif);
|
||||
int xemacpsif_input(struct netif *netif);
|
||||
#ifdef NOTNOW_BHILL
|
||||
unsigned get_IEEE_phy_speed(XLlTemac *xlltemacp);
|
||||
#endif
|
||||
s32_t xemacpsif_input(struct netif *netif);
|
||||
|
||||
/* xaxiemacif_hw.c */
|
||||
void xemacps_error_handler(XEmacPs * Temac);
|
||||
|
@ -91,13 +89,13 @@ typedef struct {
|
|||
|
||||
extern xemacpsif_s xemacpsif;
|
||||
|
||||
int is_tx_space_available(xemacpsif_s *emac);
|
||||
s32_t is_tx_space_available(xemacpsif_s *emac);
|
||||
|
||||
/* xaxiemacif_dma.c */
|
||||
/* xemacpsif_dma.c */
|
||||
|
||||
XStatus init_axi_dma(struct xemac_s *xemac);
|
||||
void process_sent_bds(XEmacPs_BdRing *txring);
|
||||
unsigned Phy_Setup (XEmacPs *xemacpsp);
|
||||
u32_t phy_setup (XEmacPs *xemacpsp, u32_t phy_addr);
|
||||
void detect_phy(XEmacPs *xemacpsp);
|
||||
void emacps_send_handler(void *arg);
|
||||
XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p);
|
||||
void emacps_recv_handler(void *arg);
|
||||
|
@ -110,8 +108,8 @@ void init_emacps(xemacpsif_s *xemacps, struct netif *netif);
|
|||
void setup_isr (struct xemac_s *xemac);
|
||||
XStatus init_dma(struct xemac_s *xemac);
|
||||
void start_emacps (xemacpsif_s *xemacps);
|
||||
void FreeTxRxPBufs(void);
|
||||
void FreeOnlyTxPBufs(void);
|
||||
void free_txrx_pbufs(void);
|
||||
void free_onlytx_pbufs(void);
|
||||
void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif);
|
||||
void clean_dma_txdescs(struct xemac_s *xemac);
|
||||
void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif);
|
||||
|
|
|
@ -85,7 +85,7 @@ static u8_t xemacps_mcast_entry_mask = 0;
|
|||
|
||||
XEmacPs_Config *mac_config;
|
||||
struct netif *NetIf;
|
||||
void FreeTxPBufs(void);
|
||||
|
||||
/*
|
||||
* this function is always called with interrupts off
|
||||
* this function also assumes that there are available BD's
|
||||
|
@ -129,27 +129,33 @@ static err_t _unbuffered_low_level_output(xemacpsif_s *xemacpsif,
|
|||
static err_t low_level_output(struct netif *netif, struct pbuf *p)
|
||||
{
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
err_t err;
|
||||
err_t err;
|
||||
s32_t freecnt;
|
||||
XEmacPs_BdRing *txring;
|
||||
|
||||
struct xemac_s *xemac = (struct xemac_s *)(netif->state);
|
||||
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
|
||||
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
|
||||
|
||||
/* check if space is available to send */
|
||||
if (is_tx_space_available(xemacpsif)) {
|
||||
freecnt = is_tx_space_available(xemacpsif);
|
||||
if (freecnt <= 5) {
|
||||
txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
|
||||
process_sent_bds(txring);
|
||||
}
|
||||
|
||||
if (is_tx_space_available(xemacpsif)) {
|
||||
_unbuffered_low_level_output(xemacpsif, p);
|
||||
err = ERR_OK;
|
||||
} else {
|
||||
#if LINK_STATS
|
||||
lwip_stats.link.drop++;
|
||||
#endif
|
||||
print("pack dropped, no space\r\n");
|
||||
printf("pack dropped, no space\r\n");
|
||||
err = ERR_MEM;
|
||||
}
|
||||
|
||||
|
||||
SYS_ARCH_UNPROTECT(lev);
|
||||
return err;
|
||||
}
|
||||
|
@ -205,7 +211,7 @@ static err_t xemacpsif_output(struct netif *netif, struct pbuf *p,
|
|||
*
|
||||
*/
|
||||
|
||||
int xemacpsif_input(struct netif *netif)
|
||||
s32_t xemacpsif_input(struct netif *netif)
|
||||
{
|
||||
struct eth_hdr *ethhdr;
|
||||
struct pbuf *p;
|
||||
|
@ -215,45 +221,45 @@ int xemacpsif_input(struct netif *netif)
|
|||
while (1)
|
||||
#endif
|
||||
{
|
||||
/* move received packet into a new pbuf */
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
p = low_level_input(netif);
|
||||
SYS_ARCH_UNPROTECT(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;
|
||||
}
|
||||
/* 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;
|
||||
/* points to packet payload, which starts with an Ethernet header */
|
||||
ethhdr = p->payload;
|
||||
|
||||
#if LINK_STATS
|
||||
lwip_stats.link.recv++;
|
||||
#endif /* LINK_STATS */
|
||||
#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, ("xemacpsif_input: IP input error\r\n"));
|
||||
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, ("xemacpsif_input: IP input error\r\n"));
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -262,12 +268,12 @@ int xemacpsif_input(struct netif *netif)
|
|||
|
||||
static err_t low_level_init(struct netif *netif)
|
||||
{
|
||||
unsigned mac_address = (unsigned)(netif->state);
|
||||
u32_t mac_address = (u32_t)(netif->state);
|
||||
struct xemac_s *xemac;
|
||||
xemacpsif_s *xemacpsif;
|
||||
u32 dmacrreg;
|
||||
|
||||
int Status = XST_SUCCESS;
|
||||
s32_t status = XST_SUCCESS;
|
||||
|
||||
NetIf = netif;
|
||||
|
||||
|
@ -312,9 +318,9 @@ static err_t low_level_init(struct netif *netif)
|
|||
/* obtain config of this emac */
|
||||
mac_config = (XEmacPs_Config *)xemacps_lookup_config((unsigned)netif->state);
|
||||
|
||||
Status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
|
||||
status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
|
||||
mac_config->BaseAddress);
|
||||
if (Status != XST_SUCCESS) {
|
||||
if (status != XST_SUCCESS) {
|
||||
xil_printf("In %s:EmacPs Configuration Failed....\r\n", __func__);
|
||||
}
|
||||
|
||||
|
@ -342,17 +348,17 @@ static err_t low_level_init(struct netif *netif)
|
|||
void HandleEmacPsError(struct xemac_s *xemac)
|
||||
{
|
||||
xemacpsif_s *xemacpsif;
|
||||
int Status = XST_SUCCESS;
|
||||
s32_t status = XST_SUCCESS;
|
||||
u32 dmacrreg;
|
||||
|
||||
SYS_ARCH_DECL_PROTECT(lev);
|
||||
SYS_ARCH_PROTECT(lev);
|
||||
|
||||
FreeTxRxPBufs();
|
||||
free_txrx_pbufs();
|
||||
xemacpsif = (xemacpsif_s *)(xemac->state);
|
||||
Status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
|
||||
status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
|
||||
mac_config->BaseAddress);
|
||||
if (Status != XST_SUCCESS) {
|
||||
if (status != XST_SUCCESS) {
|
||||
xil_printf("In %s:EmacPs Configuration Failed....\r\n", __func__);
|
||||
}
|
||||
/* initialize the mac */
|
||||
|
@ -382,7 +388,7 @@ void HandleTxErrors(struct xemac_s *xemac)
|
|||
netctrlreg = netctrlreg & (~XEMACPS_NWCTRL_TXEN_MASK);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET, netctrlreg);
|
||||
FreeOnlyTxPBufs();
|
||||
free_onlytx_pbufs();
|
||||
|
||||
clean_dma_txdescs(xemac);
|
||||
netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
|
||||
|
|
|
@ -53,9 +53,6 @@
|
|||
#include "timers.h"
|
||||
#endif
|
||||
|
||||
/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
|
||||
*** to run it on a PEEP board
|
||||
***/
|
||||
|
||||
#define INTC_BASE_ADDR XPAR_SCUGIC_CPU_BASEADDR
|
||||
#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_DIST_BASEADDR
|
||||
|
@ -63,11 +60,55 @@
|
|||
/* Byte alignment of BDs */
|
||||
#define BD_ALIGNMENT (XEMACPS_DMABD_MINIMUM_ALIGNMENT*2)
|
||||
|
||||
static int tx_pbufs_storage[XLWIP_CONFIG_N_TX_DESC];
|
||||
static int rx_pbufs_storage[XLWIP_CONFIG_N_RX_DESC];
|
||||
static s32_t tx_pbufs_storage[XLWIP_CONFIG_N_TX_DESC];
|
||||
static s32_t rx_pbufs_storage[XLWIP_CONFIG_N_RX_DESC];
|
||||
|
||||
static int EmacIntrNum;
|
||||
extern u8 _end;
|
||||
static s32_t emac_intr_num;
|
||||
|
||||
/******************************************************************************
|
||||
* Each BD is of 8 bytes of size and the BDs (BD chain) need to be put
|
||||
* at uncached memory location. If they are not put at uncached
|
||||
* locations, the user needs to flush or invalidate for each BD/packet.
|
||||
* However, the flush or invalidate can happen over a cache line which can
|
||||
* span multiple BDs. This means a flush or invalidate of one BD can actually
|
||||
* flush/invalidate multiple BDs adjacent to the targeted BD.Assuming that
|
||||
* the user and hardware both update the BD fields, this operation from user
|
||||
* can potentially overwrite the updates done by hardware or user.
|
||||
* To avoid this, it is always safe to put the BD chains for Rx and tx side
|
||||
* at uncached memory location.
|
||||
*
|
||||
* The Xilinx standalone BSP for Cortex A9 implements only primary page tables.
|
||||
* Each table entry corresponds to 1 MB of address map. This means, if a memory
|
||||
* region has to be made uncached, the minimum granularity will be of 1 MB.
|
||||
*
|
||||
* The implementation below allocates a 1 MB of u8 array aligned to 1 MB.
|
||||
* This ensures that this array is put at 1 MB aligned memory (e.g. 0x1200000)
|
||||
* and accupies memory of 1 MB. The init_dma function then changes 1 MB of this
|
||||
* region to make it uncached (strongly ordered).
|
||||
* This increases the bss section of the program significantly and can be a
|
||||
* wastage of memory. The reason beings, BDs will hardly occupy few KBs of
|
||||
* memory and the rest of 1 MB of memory will be unused.
|
||||
*
|
||||
* If a program uses other peripherals that have DMAs/bus masters and need
|
||||
* uncached memory, they may also end of following the same approach. This
|
||||
* definitely aggravates the memory wastage issue. To avoid all this, the user
|
||||
* can create a new 1 MB section in the linker script and reserve it for such
|
||||
* use cases that need uncached memory location. They can then have their own
|
||||
* memory allocation logic in their application that allocates uncached memory
|
||||
* from this 1 MB location. For such a case, changes need to be done in this
|
||||
* file and appropriate uncached memory allocated through other means can be
|
||||
* used.
|
||||
*
|
||||
* The present implementation here allocates 1 MB of uncached memory. It
|
||||
* reserves of 64 KB of memory for each BD chain. 64 KB of memory means 8192 of
|
||||
* BDs for each BD chain which is more than enough for any application.
|
||||
* Assuming that both emac0 and emac1 are present, 256 KB of memory is allocated
|
||||
* for BDs. The rest 768 KB of memory is just unused.
|
||||
*********************************************************************************/
|
||||
|
||||
u8_t bd_space[0x100000] __attribute__ ((aligned (0x100000)));
|
||||
static volatile u32_t bd_space_index = 0;
|
||||
static volatile u32_t bd_space_attr_set = 0;
|
||||
|
||||
#ifdef OS_IS_FREERTOS
|
||||
long xInsideISR = 0;
|
||||
|
@ -77,10 +118,10 @@ long xInsideISR = 0;
|
|||
(((u32)bdptr - (u32)(ringptr)->BaseBdAddr) / (ringptr)->Separation)
|
||||
|
||||
|
||||
int is_tx_space_available(xemacpsif_s *emac)
|
||||
s32_t is_tx_space_available(xemacpsif_s *emac)
|
||||
{
|
||||
XEmacPs_BdRing *txring;
|
||||
int freecnt = 0;
|
||||
s32_t freecnt = 0;
|
||||
|
||||
txring = &(XEmacPs_GetTxRing(&emac->emacps));
|
||||
|
||||
|
@ -92,13 +133,13 @@ int is_tx_space_available(xemacpsif_s *emac)
|
|||
void process_sent_bds(XEmacPs_BdRing *txring)
|
||||
{
|
||||
XEmacPs_Bd *txbdset;
|
||||
XEmacPs_Bd *CurBdPntr;
|
||||
int n_bds;
|
||||
XStatus Status;
|
||||
int n_pbufs_freed = 0;
|
||||
unsigned int BdIndex;
|
||||
XEmacPs_Bd *curbdpntr;
|
||||
s32_t n_bds;
|
||||
XStatus status;
|
||||
s32_t n_pbufs_freed = 0;
|
||||
u32_t bdindex;
|
||||
struct pbuf *p;
|
||||
unsigned int *Temp;
|
||||
u32_t *temp;
|
||||
|
||||
while (1) {
|
||||
/* obtain processed BD's */
|
||||
|
@ -109,29 +150,29 @@ void process_sent_bds(XEmacPs_BdRing *txring)
|
|||
}
|
||||
/* free the processed BD's */
|
||||
n_pbufs_freed = n_bds;
|
||||
CurBdPntr = txbdset;
|
||||
curbdpntr = txbdset;
|
||||
while (n_pbufs_freed > 0) {
|
||||
BdIndex = XEMACPS_BD_TO_INDEX(txring, CurBdPntr);
|
||||
Temp = (unsigned int *)CurBdPntr;
|
||||
*Temp = 0;
|
||||
Temp++;
|
||||
*Temp = 0x80000000;
|
||||
if (BdIndex == (XLWIP_CONFIG_N_TX_DESC - 1)) {
|
||||
*Temp = 0xC0000000;
|
||||
bdindex = XEMACPS_BD_TO_INDEX(txring, curbdpntr);
|
||||
temp = (u32_t *)curbdpntr;
|
||||
*temp = 0;
|
||||
temp++;
|
||||
*temp = 0x80000000;
|
||||
if (bdindex == (XLWIP_CONFIG_N_TX_DESC - 1)) {
|
||||
*temp = 0xC0000000;
|
||||
}
|
||||
|
||||
p = (struct pbuf *)tx_pbufs_storage[BdIndex];
|
||||
p = (struct pbuf *)tx_pbufs_storage[bdindex];
|
||||
if(p != NULL) {
|
||||
pbuf_free(p);
|
||||
}
|
||||
tx_pbufs_storage[BdIndex] = 0;
|
||||
CurBdPntr = XEmacPs_BdRingNext(txring, CurBdPntr);
|
||||
tx_pbufs_storage[bdindex] = 0;
|
||||
curbdpntr = XEmacPs_BdRingNext(txring, curbdpntr);
|
||||
n_pbufs_freed--;
|
||||
dsb();
|
||||
}
|
||||
|
||||
Status = XEmacPs_BdRingFree(txring, n_bds, txbdset);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_BdRingFree(txring, n_bds, txbdset);
|
||||
if (status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("Failure while freeing in Tx Done ISR\r\n"));
|
||||
}
|
||||
}
|
||||
|
@ -142,19 +183,19 @@ void emacps_send_handler(void *arg)
|
|||
{
|
||||
struct xemac_s *xemac;
|
||||
xemacpsif_s *xemacpsif;
|
||||
XEmacPs_BdRing *TxRingPtr;
|
||||
unsigned int regval;
|
||||
XEmacPs_BdRing *txringptr;
|
||||
u32_t regval;
|
||||
#ifdef OS_IS_FREERTOS
|
||||
xInsideISR++;
|
||||
#endif
|
||||
xemac = (struct xemac_s *)(arg);
|
||||
xemacpsif = (xemacpsif_s *)(xemac->state);
|
||||
TxRingPtr = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
|
||||
txringptr = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
|
||||
regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET);
|
||||
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,XEMACPS_TXSR_OFFSET, regval);
|
||||
|
||||
/* If Transmit done interrupt is asserted, process completed BD's */
|
||||
process_sent_bds(TxRingPtr);
|
||||
process_sent_bds(txringptr);
|
||||
#ifdef OS_IS_FREERTOS
|
||||
xInsideISR--;
|
||||
#endif
|
||||
|
@ -163,21 +204,17 @@ void emacps_send_handler(void *arg)
|
|||
XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p)
|
||||
{
|
||||
struct pbuf *q;
|
||||
int n_pbufs;
|
||||
s32_t n_pbufs;
|
||||
XEmacPs_Bd *txbdset, *txbd, *last_txbd = NULL;
|
||||
XEmacPs_Bd *temp_txbd;
|
||||
XStatus Status;
|
||||
XStatus status;
|
||||
XEmacPs_BdRing *txring;
|
||||
unsigned int BdIndex;
|
||||
unsigned int lev;
|
||||
u32_t bdindex;
|
||||
u32_t lev;
|
||||
|
||||
lev = mfcpsr();
|
||||
mtcpsr(lev | 0x000000C0);
|
||||
|
||||
#ifdef PEEP
|
||||
while((XEmacPs_ReadReg((xemacpsif->emacps).Config.BaseAddress,
|
||||
XEMACPS_TXSR_OFFSET)) & 0x08);
|
||||
#endif
|
||||
txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
|
||||
|
||||
/* first count the number of pbufs */
|
||||
|
@ -185,25 +222,25 @@ XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p)
|
|||
n_pbufs++;
|
||||
|
||||
/* obtain as many BD's */
|
||||
Status = XEmacPs_BdRingAlloc(txring, n_pbufs, &txbdset);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_BdRingAlloc(txring, n_pbufs, &txbdset);
|
||||
if (status != XST_SUCCESS) {
|
||||
mtcpsr(lev);
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error allocating TxBD\r\n"));
|
||||
return ERR_IF;
|
||||
return XST_FAILURE;
|
||||
}
|
||||
|
||||
for(q = p, txbd = txbdset; q != NULL; q = q->next) {
|
||||
BdIndex = XEMACPS_BD_TO_INDEX(txring, txbd);
|
||||
if (tx_pbufs_storage[BdIndex] != 0) {
|
||||
bdindex = XEMACPS_BD_TO_INDEX(txring, txbd);
|
||||
if (tx_pbufs_storage[bdindex] != 0) {
|
||||
mtcpsr(lev);
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("PBUFS not available\r\n"));
|
||||
return ERR_IF;
|
||||
return XST_FAILURE;
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
Xil_DCacheFlushRange((unsigned int)q->payload, (unsigned)q->len);
|
||||
Xil_DCacheFlushRange((u32_t)q->payload, (u32_t)q->len);
|
||||
|
||||
XEmacPs_BdSetAddressTx(txbd, (u32)q->payload);
|
||||
if (q->len > (XEMACPS_MAX_FRAME_SIZE - 18))
|
||||
|
@ -211,16 +248,14 @@ XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p)
|
|||
else
|
||||
XEmacPs_BdSetLength(txbd, q->len & 0x3FFF);
|
||||
|
||||
tx_pbufs_storage[BdIndex] = (int)q;
|
||||
tx_pbufs_storage[bdindex] = (s32_t)q;
|
||||
|
||||
pbuf_ref(q);
|
||||
last_txbd = txbd;
|
||||
XEmacPs_BdClearLast(txbd);
|
||||
dsb();
|
||||
txbd = XEmacPs_BdRingNext(txring, txbd);
|
||||
}
|
||||
XEmacPs_BdSetLast(last_txbd);
|
||||
dsb();
|
||||
/* For fragmented packets, remember the 1st BD allocated for the 1st
|
||||
packet fragment. The used bit for this BD should be cleared at the end
|
||||
after clearing out used bits for other fragments. For packets without
|
||||
|
@ -234,89 +269,88 @@ XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p)
|
|||
txbd = XEmacPs_BdRingNext(txring, txbd);
|
||||
}
|
||||
XEmacPs_BdClearTxUsed(temp_txbd);
|
||||
dsb();
|
||||
|
||||
Status = XEmacPs_BdRingToHw(txring, n_pbufs, txbdset);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_BdRingToHw(txring, n_pbufs, txbdset);
|
||||
if (status != XST_SUCCESS) {
|
||||
mtcpsr(lev);
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error submitting TxBD\r\n"));
|
||||
return ERR_IF;
|
||||
return XST_FAILURE;
|
||||
}
|
||||
dsb();
|
||||
/* Start transmit */
|
||||
XEmacPs_WriteReg((xemacpsif->emacps).Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET,
|
||||
(XEmacPs_ReadReg((xemacpsif->emacps).Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET) | XEMACPS_NWCTRL_STARTTX_MASK));
|
||||
dsb();
|
||||
|
||||
mtcpsr(lev);
|
||||
return Status;
|
||||
return status;
|
||||
}
|
||||
|
||||
void setup_rx_bds(XEmacPs_BdRing *rxring)
|
||||
{
|
||||
XEmacPs_Bd *rxbd;
|
||||
XStatus Status;
|
||||
XStatus status;
|
||||
struct pbuf *p;
|
||||
unsigned int FreeBds;
|
||||
unsigned int BdIndex;
|
||||
unsigned int *Temp;
|
||||
|
||||
FreeBds = XEmacPs_BdRingGetFreeCnt (rxring);
|
||||
while (FreeBds > 0) {
|
||||
FreeBds--;
|
||||
Status = XEmacPs_BdRingAlloc(rxring, 1, &rxbd);
|
||||
if (Status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("setup_rx_bds: Error allocating RxBD\r\n"));
|
||||
return;
|
||||
}
|
||||
BdIndex = XEMACPS_BD_TO_INDEX(rxring, rxbd);
|
||||
Temp = (unsigned int *)rxbd;
|
||||
*Temp = 0;
|
||||
if (BdIndex == (XLWIP_CONFIG_N_RX_DESC - 1)) {
|
||||
*Temp = 0x00000002;
|
||||
}
|
||||
Temp++;
|
||||
*Temp = 0;
|
||||
u32_t freebds;
|
||||
u32_t bdindex;
|
||||
u32_t *temp;
|
||||
|
||||
freebds = XEmacPs_BdRingGetFreeCnt (rxring);
|
||||
while (freebds > 0) {
|
||||
freebds--;
|
||||
p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
|
||||
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"));
|
||||
XEmacPs_BdRingUnAlloc(rxring, 1, rxbd);
|
||||
dsb();
|
||||
printf("unable to alloc pbuf in recv_handler\r\n");
|
||||
return;
|
||||
}
|
||||
XEmacPs_BdSetAddressRx(rxbd, (u32)p->payload);
|
||||
dsb();
|
||||
|
||||
rx_pbufs_storage[BdIndex] = (int)p;
|
||||
Status = XEmacPs_BdRingToHw(rxring, 1, rxbd);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_BdRingAlloc(rxring, 1, &rxbd);
|
||||
if (status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("setup_rx_bds: Error allocating RxBD\r\n"));
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
status = XEmacPs_BdRingToHw(rxring, 1, rxbd);
|
||||
if (status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("Error committing RxBD to hardware: "));
|
||||
if (Status == XST_DMA_SG_LIST_ERROR)
|
||||
if (status == XST_DMA_SG_LIST_ERROR)
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("XST_DMA_SG_LIST_ERROR: this function was called out of sequence with XEmacPs_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"));
|
||||
|
||||
pbuf_free(p);
|
||||
XEmacPs_BdRingUnAlloc(rxring, 1, rxbd);
|
||||
return;
|
||||
}
|
||||
Xil_DCacheInvalidateRange((u32_t)p->payload, (u32_t)XEMACPS_MAX_FRAME_SIZE);
|
||||
bdindex = XEMACPS_BD_TO_INDEX(rxring, rxbd);
|
||||
temp = (u32_t *)rxbd;
|
||||
*temp = 0;
|
||||
if (bdindex == (XLWIP_CONFIG_N_RX_DESC - 1)) {
|
||||
*temp = 0x00000002;
|
||||
}
|
||||
temp++;
|
||||
*temp = 0;
|
||||
|
||||
XEmacPs_BdSetAddressRx(rxbd, (u32_t)p->payload);
|
||||
rx_pbufs_storage[bdindex] = (s32_t)p;
|
||||
}
|
||||
}
|
||||
|
||||
void emacps_recv_handler(void *arg)
|
||||
{
|
||||
struct pbuf *p;
|
||||
XEmacPs_Bd *rxbdset, *CurBdPtr;
|
||||
XEmacPs_Bd *rxbdset, *curbdptr;
|
||||
struct xemac_s *xemac;
|
||||
xemacpsif_s *xemacpsif;
|
||||
XEmacPs_BdRing *rxring;
|
||||
volatile int bd_processed;
|
||||
int rx_bytes, k;
|
||||
unsigned int BdIndex;
|
||||
unsigned int regval;
|
||||
volatile s32_t bd_processed;
|
||||
s32_t rx_bytes, k;
|
||||
u32_t bdindex;
|
||||
u32_t regval;
|
||||
|
||||
xemac = (struct xemac_s *)(arg);
|
||||
xemacpsif = (xemacpsif_s *)(xemac->state);
|
||||
|
@ -337,22 +371,21 @@ void emacps_recv_handler(void *arg)
|
|||
while(1) {
|
||||
|
||||
bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset);
|
||||
|
||||
if (bd_processed <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (k = 0, CurBdPtr=rxbdset; k < bd_processed; k++) {
|
||||
for (k = 0, curbdptr=rxbdset; k < bd_processed; k++) {
|
||||
|
||||
BdIndex = XEMACPS_BD_TO_INDEX(rxring, CurBdPtr);
|
||||
p = (struct pbuf *)rx_pbufs_storage[BdIndex];
|
||||
bdindex = XEMACPS_BD_TO_INDEX(rxring, curbdptr);
|
||||
p = (struct pbuf *)rx_pbufs_storage[bdindex];
|
||||
|
||||
/*
|
||||
* Adjust the buffer size to the actual number of bytes received.
|
||||
*/
|
||||
rx_bytes = XEmacPs_BdGetLength(CurBdPtr);
|
||||
rx_bytes = XEmacPs_BdGetLength(curbdptr);
|
||||
pbuf_realloc(p, rx_bytes);
|
||||
Xil_DCacheInvalidateRange((unsigned int)p->payload, (unsigned)XEMACPS_MAX_FRAME_SIZE);
|
||||
|
||||
/* store it in the receive queue,
|
||||
* where it'll be processed by a different handler
|
||||
*/
|
||||
|
@ -367,7 +400,7 @@ void emacps_recv_handler(void *arg)
|
|||
sys_sem_signal(&xemac->sem_rx_data_available);
|
||||
#endif
|
||||
}
|
||||
CurBdPtr = XEmacPs_BdRingNext( rxring, CurBdPtr);
|
||||
curbdptr = XEmacPs_BdRingNext( rxring, curbdptr);
|
||||
}
|
||||
/* free up the BD's */
|
||||
XEmacPs_BdRingFree(rxring, bd_processed, rxbdset);
|
||||
|
@ -382,61 +415,62 @@ void emacps_recv_handler(void *arg)
|
|||
|
||||
void clean_dma_txdescs(struct xemac_s *xemac)
|
||||
{
|
||||
XEmacPs_Bd BdTemplate;
|
||||
XEmacPs_BdRing *TxRingPtr;
|
||||
XEmacPs_Bd bdtemplate;
|
||||
XEmacPs_BdRing *txringptr;
|
||||
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
|
||||
|
||||
TxRingPtr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
|
||||
txringptr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
|
||||
|
||||
XEmacPs_BdClear(&BdTemplate);
|
||||
XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
|
||||
XEmacPs_BdClear(&bdtemplate);
|
||||
XEmacPs_BdSetStatus(&bdtemplate, XEMACPS_TXBUF_USED_MASK);
|
||||
|
||||
/*
|
||||
* Create the TxBD ring
|
||||
*/
|
||||
XEmacPs_BdRingCreate(TxRingPtr, (u32) xemacpsif->tx_bdspace,
|
||||
XEmacPs_BdRingCreate(txringptr, (u32) xemacpsif->tx_bdspace,
|
||||
(u32) xemacpsif->tx_bdspace, BD_ALIGNMENT,
|
||||
XLWIP_CONFIG_N_TX_DESC);
|
||||
XEmacPs_BdRingClone(TxRingPtr, &BdTemplate, XEMACPS_SEND);
|
||||
XEmacPs_BdRingClone(txringptr, &bdtemplate, XEMACPS_SEND);
|
||||
}
|
||||
|
||||
|
||||
XStatus init_dma(struct xemac_s *xemac)
|
||||
{
|
||||
XEmacPs_Bd BdTemplate;
|
||||
XEmacPs_BdRing *RxRingPtr, *TxRingPtr;
|
||||
XEmacPs_Bd bdtemplate;
|
||||
XEmacPs_BdRing *rxringptr, *txringptr;
|
||||
XEmacPs_Bd *rxbd;
|
||||
struct pbuf *p;
|
||||
XStatus Status;
|
||||
int i;
|
||||
unsigned int BdIndex;
|
||||
char *endAdd = &_end;
|
||||
/*
|
||||
* Align the BD starte address to 1 MB boundary.
|
||||
*/
|
||||
char *endAdd_aligned = (char *)(((int)endAdd + 0x100000) & (~0xFFFFF));
|
||||
XStatus status;
|
||||
s32_t i;
|
||||
u32_t bdindex;
|
||||
volatile u32_t tempaddress;
|
||||
|
||||
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
|
||||
struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
|
||||
|
||||
/*
|
||||
* The BDs need to be allocated in uncached memory. Hence the 1 MB
|
||||
* address range that starts at address 0xFF00000 is made uncached
|
||||
* address range allocated for Bd_Space is made uncached
|
||||
* by setting appropriate attributes in the translation table.
|
||||
* The Bd_Space is aligned to 1MB and has a size of 1 MB. This ensures
|
||||
* a reserved uncached area used only for BDs.
|
||||
*/
|
||||
Xil_SetTlbAttributes((int)endAdd_aligned, 0xc02); // addr, attr
|
||||
if (bd_space_attr_set == 0) {
|
||||
Xil_SetTlbAttributes((s32_t)bd_space, 0xc02); // addr, attr
|
||||
bd_space_attr_set = 1;
|
||||
}
|
||||
|
||||
RxRingPtr = &XEmacPs_GetRxRing(&xemacpsif->emacps);
|
||||
TxRingPtr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("RxRingPtr: 0x%08x\r\n", RxRingPtr));
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("TxRingPtr: 0x%08x\r\n", TxRingPtr));
|
||||
rxringptr = &XEmacPs_GetRxRing(&xemacpsif->emacps);
|
||||
txringptr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rxringptr: 0x%08x\r\n", rxringptr));
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("txringptr: 0x%08x\r\n", txringptr));
|
||||
|
||||
xemacpsif->rx_bdspace = (void *)endAdd_aligned;
|
||||
/*
|
||||
* We allocate 65536 bytes for Rx BDs which can accomodate a
|
||||
* maximum of 8192 BDs which is much more than any application
|
||||
* will ever need.
|
||||
*/
|
||||
xemacpsif->tx_bdspace = (void *)(endAdd_aligned + 0x10000);
|
||||
/* Allocate 64k for Rx and Tx bds each to take care of extreme cases */
|
||||
tempaddress = (u32_t)&(bd_space[bd_space_index]);
|
||||
xemacpsif->rx_bdspace = (void *)tempaddress;
|
||||
bd_space_index += 0x10000;
|
||||
tempaddress = (u32_t)&(bd_space[bd_space_index]);
|
||||
xemacpsif->tx_bdspace = (void *)tempaddress;
|
||||
bd_space_index += 0x10000;
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("rx_bdspace: 0x%08x\r\n", xemacpsif->rx_bdspace));
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("tx_bdspace: 0x%08x\r\n", xemacpsif->tx_bdspace));
|
||||
|
@ -444,7 +478,7 @@ XStatus init_dma(struct xemac_s *xemac)
|
|||
if (!xemacpsif->rx_bdspace || !xemacpsif->tx_bdspace) {
|
||||
xil_printf("%s@%d: Error: Unable to allocate memory for TX/RX buffer descriptors",
|
||||
__FILE__, __LINE__);
|
||||
return XST_FAILURE;
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -453,43 +487,43 @@ XStatus init_dma(struct xemac_s *xemac)
|
|||
* 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.
|
||||
*/
|
||||
XEmacPs_BdClear(&BdTemplate);
|
||||
XEmacPs_BdClear(&bdtemplate);
|
||||
|
||||
/*
|
||||
* Create the RxBD ring
|
||||
*/
|
||||
|
||||
Status = XEmacPs_BdRingCreate(RxRingPtr, (u32) xemacpsif->rx_bdspace,
|
||||
status = XEmacPs_BdRingCreate(rxringptr, (u32) xemacpsif->rx_bdspace,
|
||||
(u32) xemacpsif->rx_bdspace, BD_ALIGNMENT,
|
||||
XLWIP_CONFIG_N_RX_DESC);
|
||||
|
||||
if (Status != XST_SUCCESS) {
|
||||
if (status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("Error setting up RxBD space\r\n"));
|
||||
return XST_FAILURE;
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
Status = XEmacPs_BdRingClone(RxRingPtr, &BdTemplate, XEMACPS_RECV);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_BdRingClone(rxringptr, &bdtemplate, XEMACPS_RECV);
|
||||
if (status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("Error initializing RxBD space\r\n"));
|
||||
return XST_FAILURE;
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
XEmacPs_BdClear(&BdTemplate);
|
||||
XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK);
|
||||
XEmacPs_BdClear(&bdtemplate);
|
||||
XEmacPs_BdSetStatus(&bdtemplate, XEMACPS_TXBUF_USED_MASK);
|
||||
/*
|
||||
* Create the TxBD ring
|
||||
*/
|
||||
Status = XEmacPs_BdRingCreate(TxRingPtr, (u32) xemacpsif->tx_bdspace,
|
||||
status = XEmacPs_BdRingCreate(txringptr, (u32) xemacpsif->tx_bdspace,
|
||||
(u32) xemacpsif->tx_bdspace, BD_ALIGNMENT,
|
||||
XLWIP_CONFIG_N_TX_DESC);
|
||||
|
||||
if (Status != XST_SUCCESS) {
|
||||
return XST_FAILURE;
|
||||
if (status != XST_SUCCESS) {
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
/* We reuse the bd template, as the same one will work for both rx and tx. */
|
||||
Status = XEmacPs_BdRingClone(TxRingPtr, &BdTemplate, XEMACPS_SEND);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_BdRingClone(txringptr, &bdtemplate, XEMACPS_SEND);
|
||||
if (status != XST_SUCCESS) {
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
|
@ -497,33 +531,35 @@ XStatus init_dma(struct xemac_s *xemac)
|
|||
* Allocate RX descriptors, 1 RxBD at a time.
|
||||
*/
|
||||
for (i = 0; i < XLWIP_CONFIG_N_RX_DESC; i++) {
|
||||
Status = XEmacPs_BdRingAlloc(RxRingPtr, 1, &rxbd);
|
||||
if (Status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("init_dma: Error allocating RxBD\r\n"));
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
|
||||
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;
|
||||
printf("unable to alloc pbuf in init_dma\r\n");
|
||||
return ERR_IF;
|
||||
}
|
||||
status = XEmacPs_BdRingAlloc(rxringptr, 1, &rxbd);
|
||||
if (status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("init_dma: Error allocating RxBD\r\n"));
|
||||
pbuf_free(p);
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
XEmacPs_BdSetAddressRx(rxbd, (u32)p->payload);
|
||||
|
||||
BdIndex = XEMACPS_BD_TO_INDEX(RxRingPtr, rxbd);
|
||||
rx_pbufs_storage[BdIndex] = (int)p;
|
||||
|
||||
/* Enqueue to HW */
|
||||
Status = XEmacPs_BdRingToHw(RxRingPtr, 1, rxbd);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_BdRingToHw(rxringptr, 1, rxbd);
|
||||
if (status != XST_SUCCESS) {
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("Error: committing RxBD to HW\r\n"));
|
||||
return XST_FAILURE;
|
||||
pbuf_free(p);
|
||||
XEmacPs_BdRingUnAlloc(rxringptr, 1, rxbd);
|
||||
return ERR_IF;
|
||||
}
|
||||
|
||||
Xil_DCacheInvalidateRange((u32_t)p->payload, (u32_t)XEMACPS_MAX_FRAME_SIZE);
|
||||
XEmacPs_BdSetAddressRx(rxbd, (u32_t)p->payload);
|
||||
|
||||
bdindex = XEMACPS_BD_TO_INDEX(rxringptr, rxbd);
|
||||
rx_pbufs_storage[bdindex] = (s32_t)p;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -538,7 +574,7 @@ XStatus init_dma(struct xemac_s *xemac)
|
|||
* Enable the interrupt for emacps.
|
||||
*/
|
||||
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, (u32) xtopologyp->scugic_emac_intr);
|
||||
EmacIntrNum = (u32) xtopologyp->scugic_emac_intr;
|
||||
emac_intr_num = (u32) xtopologyp->scugic_emac_intr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -558,8 +594,8 @@ XStatus init_dma(struct xemac_s *xemac)
|
|||
|
||||
void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
|
||||
{
|
||||
unsigned long regctrl;
|
||||
unsigned long tempcntr;
|
||||
u32_t regctrl;
|
||||
u32_t tempcntr;
|
||||
|
||||
tempcntr = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET);
|
||||
if ((!tempcntr) && (!(xemacpsif->last_rx_frms_cntr))) {
|
||||
|
@ -575,46 +611,46 @@ void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
|
|||
xemacpsif->last_rx_frms_cntr = tempcntr;
|
||||
}
|
||||
|
||||
void FreeTxRxPBufs(void)
|
||||
void free_txrx_pbufs(void)
|
||||
{
|
||||
int Index;
|
||||
s32_t index;
|
||||
struct pbuf *p;
|
||||
|
||||
for (Index = 0; Index < XLWIP_CONFIG_N_TX_DESC; Index++) {
|
||||
if (tx_pbufs_storage[Index] != 0) {
|
||||
p = (struct pbuf *)tx_pbufs_storage[Index];
|
||||
for (index = 0; index < XLWIP_CONFIG_N_TX_DESC; index++) {
|
||||
if (tx_pbufs_storage[index] != 0) {
|
||||
p = (struct pbuf *)tx_pbufs_storage[index];
|
||||
pbuf_free(p);
|
||||
tx_pbufs_storage[Index] = 0;
|
||||
tx_pbufs_storage[index] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (Index = 0; Index < XLWIP_CONFIG_N_RX_DESC; Index++) {
|
||||
p = (struct pbuf *)rx_pbufs_storage[Index];
|
||||
for (index = 0; index < XLWIP_CONFIG_N_RX_DESC; index++) {
|
||||
p = (struct pbuf *)rx_pbufs_storage[index];
|
||||
pbuf_free(p);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void FreeOnlyTxPBufs(void)
|
||||
void free_onlytx_pbufs(void)
|
||||
{
|
||||
int Index;
|
||||
s32_t index;
|
||||
struct pbuf *p;
|
||||
|
||||
for (Index = 0; Index < XLWIP_CONFIG_N_TX_DESC; Index++) {
|
||||
if (tx_pbufs_storage[Index] != 0) {
|
||||
p = (struct pbuf *)tx_pbufs_storage[Index];
|
||||
for (index = 0; index < XLWIP_CONFIG_N_TX_DESC; index++) {
|
||||
if (tx_pbufs_storage[index] != 0) {
|
||||
p = (struct pbuf *)tx_pbufs_storage[index];
|
||||
pbuf_free(p);
|
||||
tx_pbufs_storage[Index] = 0;
|
||||
tx_pbufs_storage[index] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EmacDisableIntr(void)
|
||||
void emac_disable_intr(void)
|
||||
{
|
||||
XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, EmacIntrNum);
|
||||
XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, emac_intr_num);
|
||||
}
|
||||
|
||||
void EmacEnableIntr(void)
|
||||
void emac_enable_intr(void)
|
||||
{
|
||||
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, EmacIntrNum);
|
||||
XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, emac_intr_num);
|
||||
}
|
||||
|
|
|
@ -33,34 +33,42 @@
|
|||
#include "netif/xemacpsif.h"
|
||||
#include "lwipopts.h"
|
||||
|
||||
/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
|
||||
*** to run it on a PEEP board
|
||||
***/
|
||||
#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 || \
|
||||
XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
|
||||
#define PCM_PMA_CORE_PRESENT
|
||||
#else
|
||||
#undef PCM_PMA_CORE_PRESENT
|
||||
#endif
|
||||
|
||||
unsigned int link_speed = 100;
|
||||
u32_t link_speed = 100;
|
||||
extern XEmacPs_Config XEmacPs_ConfigTable[];
|
||||
extern u32_t phymapemac0[32];
|
||||
extern u32_t phymapemac1[32];
|
||||
|
||||
XEmacPs_Config *xemacps_lookup_config(unsigned mac_base)
|
||||
{
|
||||
extern XEmacPs_Config XEmacPs_ConfigTable[];
|
||||
XEmacPs_Config *CfgPtr = NULL;
|
||||
int i;
|
||||
XEmacPs_Config *cfgptr = NULL;
|
||||
s32_t i;
|
||||
|
||||
for (i = 0; i < XPAR_XEMACPS_NUM_INSTANCES; i++) {
|
||||
if (XEmacPs_ConfigTable[i].BaseAddress == mac_base) {
|
||||
CfgPtr = &XEmacPs_ConfigTable[i];
|
||||
cfgptr = &XEmacPs_ConfigTable[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (CfgPtr);
|
||||
return (cfgptr);
|
||||
}
|
||||
|
||||
void init_emacps(xemacpsif_s *xemacps, struct netif *netif)
|
||||
{
|
||||
unsigned mac_address = (unsigned)(netif->state);
|
||||
u32_t mac_address = (u32_t)(netif->state);
|
||||
XEmacPs *xemacpsp;
|
||||
XEmacPs_Config *mac_config;
|
||||
int Status = XST_SUCCESS;
|
||||
s32_t status = XST_SUCCESS;
|
||||
u32_t i;
|
||||
u32_t phyfoundforemac0 = FALSE;
|
||||
u32_t phyfoundforemac1 = FALSE;
|
||||
|
||||
/* obtain config of this emac */
|
||||
mac_config = (XEmacPs_Config *)xemacps_lookup_config(mac_address);
|
||||
|
@ -68,26 +76,68 @@ void init_emacps(xemacpsif_s *xemacps, struct netif *netif)
|
|||
xemacpsp = &xemacps->emacps;
|
||||
|
||||
/* set mac address */
|
||||
Status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
|
||||
if (status != XST_SUCCESS) {
|
||||
xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
|
||||
}
|
||||
|
||||
XEmacPs_SetMdioDivisor(xemacpsp, MDC_DIV_224);
|
||||
link_speed = Phy_Setup(xemacpsp);
|
||||
|
||||
/* Please refer to file header comments for the file xemacpsif_physpeed.c
|
||||
* to know more about the PHY programming sequence.
|
||||
* For PCS PMA core, phy_setup is called with the predefined PHY address
|
||||
* exposed through xaparemeters.h
|
||||
* For RGMII case, assuming multiple PHYs can be present on the MDIO bus,
|
||||
* detect_phy is called to get the addresses of the PHY present on
|
||||
* a particular MDIO bus (emac0 or emac1). This address map is populated
|
||||
* in phymapemac0 or phymapemac1.
|
||||
* phy_setup is then called for each PHY present on the MDIO bus.
|
||||
*/
|
||||
#ifdef PCM_PMA_CORE_PRESENT
|
||||
#ifdef XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT
|
||||
link_speed = phy_setup(xemacpsp, XPAR_PCSPMA_1000BASEX_PHYADDR);
|
||||
#elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT
|
||||
link_speed = phy_setup(xemacpsp, XPAR_PCSPMA_SGMII_PHYADDR);
|
||||
#endif
|
||||
#else
|
||||
detect_phy(xemacpsp);
|
||||
for (i = 31; i > 0; i--) {
|
||||
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
|
||||
if (phymapemac0[i] == TRUE) {
|
||||
link_speed = phy_setup(xemacpsp, i);
|
||||
phyfoundforemac0 = TRUE;
|
||||
}
|
||||
} else {
|
||||
if (phymapemac1[i] == TRUE) {
|
||||
link_speed = phy_setup(xemacpsp, i);
|
||||
phyfoundforemac1 = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If no PHY was detected, use broadcast PHY address of 0 */
|
||||
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
|
||||
if (phyfoundforemac0 == FALSE)
|
||||
link_speed = phy_setup(xemacpsp, 0);
|
||||
} else {
|
||||
if (phyfoundforemac1 == FALSE)
|
||||
link_speed = phy_setup(xemacpsp, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
|
||||
/* Setting the operating speed of the MAC needs a delay. */
|
||||
{
|
||||
volatile int wait;
|
||||
volatile s32_t wait;
|
||||
for (wait=0; wait < 20000; wait++);
|
||||
}
|
||||
}
|
||||
|
||||
void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif)
|
||||
{
|
||||
unsigned mac_address = (unsigned)(netif->state);
|
||||
u32_t mac_address = (u32_t)(netif->state);
|
||||
XEmacPs *xemacpsp;
|
||||
XEmacPs_Config *mac_config;
|
||||
int Status = XST_SUCCESS;
|
||||
s32_t status = XST_SUCCESS;
|
||||
|
||||
/* obtain config of this emac */
|
||||
mac_config = (XEmacPs_Config *)xemacps_lookup_config(mac_address);
|
||||
|
@ -95,8 +145,8 @@ void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif)
|
|||
xemacpsp = &xemacps->emacps;
|
||||
|
||||
/* set mac address */
|
||||
Status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
|
||||
if (Status != XST_SUCCESS) {
|
||||
status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
|
||||
if (status != XST_SUCCESS) {
|
||||
xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
|
||||
}
|
||||
|
||||
|
@ -104,7 +154,7 @@ void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif)
|
|||
|
||||
/* Setting the operating speed of the MAC needs a delay. */
|
||||
{
|
||||
volatile int wait;
|
||||
volatile s32_t wait;
|
||||
for (wait=0; wait < 20000; wait++);
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +187,7 @@ void start_emacps (xemacpsif_s *xemacps)
|
|||
}
|
||||
|
||||
void restart_emacps_transmitter (xemacpsif_s *xemacps) {
|
||||
u32 Reg;
|
||||
u32_t Reg;
|
||||
Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
|
||||
XEMACPS_NWCTRL_OFFSET);
|
||||
Reg = Reg & (~XEMACPS_NWCTRL_TXEN_MASK);
|
||||
|
|
|
@ -1,52 +1,110 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2010 - 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Some portions copyright (c) 2010-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.
|
||||
*
|
||||
*/
|
||||
/*****************************************************************************
|
||||
* This file xemacpsif_physpeed.c implements functionalities to:
|
||||
* - Detect the available PHYs connected to a MAC
|
||||
* - Negotiate speed
|
||||
* - Configure speed
|
||||
* - Configure the SLCR registers for the negotiated speed
|
||||
*
|
||||
* In a typical use case, users of the APIs implemented in this file need to
|
||||
* do the following.
|
||||
* - Call the API detect_phy. It probes for the available PHYs connected to a MAC.
|
||||
* The MACs can be Emac0 (XPAR_XEMACPS_0_BASEADDR, 0xE000B000) or Emac1
|
||||
* (XPAR_XEMACPS_0_BASEADDR, 0xE000C000). It populates an array to notify
|
||||
* about the detected PHYs. The array phymapemac0 is used for Emac0 and
|
||||
* phymapemac1 is for Emac1.
|
||||
* - The users need to parse the corresponding arrays, phymapemac0 or phymapemac1
|
||||
* to know the available PHYs for a MAC. The users then need to call phy_setup
|
||||
* to setup the PHYs for proper speed setting. The API phy_setup should be called
|
||||
* with the PHY address for which the speed needs to be negotiated or configured.
|
||||
* In a specific use case, if 2 PHYs are connected to Emac0 with addresses of 7
|
||||
* and 11, then users get these address details from phymapemac0 (after calling
|
||||
* detect_phy) and then call phy_setup twice, with ab address of 7 and 11.
|
||||
* - Points to note: The MAC can operate at only one speed. If a MAC is connected
|
||||
* to multiple PHYs, then all PHYs must negotiate and configured for the same
|
||||
* speed.
|
||||
* - This file implements static functions to set proper SLCR clocks. As stated
|
||||
* above, all PHYs connected to a PHY must operate at same speed and the SLCR
|
||||
* clock will be setup accordingly.
|
||||
*
|
||||
* This file implements the following PHY types.
|
||||
* - The standard RGMII.
|
||||
* - It provides support for GMII to RGMII converter Xilinx IP. This Xilinx IP
|
||||
* sits on the MDIO bus with a predefined PHY address. This IP exposes register
|
||||
* that needs to be programmed with the negotiated speed.
|
||||
* For example, in a typical design, the Emac0 or Emac1 exposes GMII interface.
|
||||
* The user can then use the Xilinx IP that converts GMII to RGMII.
|
||||
* The external PHY (most typically Marvell 88E1116R) negotiates for speed
|
||||
* with the remote PHY. The implementation in this file then programs the
|
||||
* Xilinx IP with this negotiated speed. The Xilinx IP has a predefined IP
|
||||
* address exposed through xparameters.h
|
||||
* - The SGMII and 1000 BaseX PHY interfaces.
|
||||
* If the PHY interface is SGMII or 1000 BaseX a separate "get_IEEE_phy_speed"
|
||||
* is used which is different from standard RGMII "get_IEEE_phy_speed".
|
||||
* The 1000 BaseX always operates at 1000 Mbps. The SGMII interface can
|
||||
* negotiate speed accordingly.
|
||||
* For SGMII or 1000 BaseX interfaces, the detect_phy should not be called.
|
||||
* The phy addresses for these interfaces are fixed at the design time.
|
||||
*
|
||||
* Point to note:
|
||||
* A MAC can not be connected to PHYs where there is a mix between
|
||||
* SGMII or 1000 Basex or GMII/MII/RGMII.
|
||||
* In a typical multiple PHY designs, it is expected that the PHYs connected
|
||||
* will be RGMII or GMII.
|
||||
*
|
||||
* The users can choose not to negotiate speed from lwip settings GUI.
|
||||
* If they opt to choose a particular PHY speed, then the PHY will hard code
|
||||
* the speed to operate only at the corresponding speed. It will not advertise
|
||||
* any other speeds. It is users responsibility to ensure that the remote PHY
|
||||
* supports the speed programmed through the lwip gui.
|
||||
*
|
||||
* The following combination of MDIO/PHY are supported:
|
||||
* - Multiple PHYs connected to the MDIO bus of a MAC. If Emac0 MDIO is connected
|
||||
* to single/multiple PHYs, it is supported. Similarly Emac1 MDIO connected to
|
||||
* single/multiple PHYs is supported.
|
||||
* - A design where both the interfaces are present and are connected to their own
|
||||
* MDIO bus is supported.
|
||||
*
|
||||
* The following MDIO/PHY setup is not supported:
|
||||
* - A design has both the MACs present. MDIO bus is available only for one MAC
|
||||
* (Emac0 or Emac1). This MDIO bus has multiple PHYs available for both the
|
||||
* MACs. The negotiated speed for PHYs sitting on the MDIO bus of one MAC will
|
||||
* not be see for the other MAC and hence the speed/SLCR settings of the other
|
||||
* MAC cannot be programmed. Hence this kind of design will not work for
|
||||
* this implementation.
|
||||
*
|
||||
********************************************************************************/
|
||||
|
||||
#include "netif/xemacpsif.h"
|
||||
#include "lwipopts.h"
|
||||
|
@ -59,45 +117,32 @@
|
|||
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
|
||||
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
|
||||
|
||||
#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_1000_ADVERTISE_REG_OFFSET 9
|
||||
#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10
|
||||
#define IEEE_COPPER_SPECIFIC_CONTROL_REG 16
|
||||
#define IEEE_SPECIFIC_STATUS_REG 17
|
||||
#define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19
|
||||
#define IEEE_CONTROL_REG_MAC 21
|
||||
#define IEEE_PAGE_ADDRESS_REGISTER 22
|
||||
|
||||
|
||||
#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_CTRL_RESET_MASK 0x8000
|
||||
#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000
|
||||
#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 IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030
|
||||
|
||||
#define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800
|
||||
#define IEEE_PAUSE_MASK 0x0400
|
||||
#define IEEE_AUTONEG_ERROR_MASK 0x8000
|
||||
|
@ -115,13 +160,10 @@
|
|||
#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8)
|
||||
#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140)
|
||||
#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144)
|
||||
#define SLCR_LOCK_KEY_VALUE 0x767B
|
||||
#define SLCR_UNLOCK_KEY_VALUE 0xDF0D
|
||||
#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
|
||||
#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF
|
||||
|
||||
#define EMAC0_BASE_ADDRESS 0xE000B000
|
||||
#define EMAC1_BASE_ADDRESS 0xE000C000
|
||||
#define SLCR_LOCK_KEY_VALUE 0x767B
|
||||
#define SLCR_UNLOCK_KEY_VALUE 0xDF0D
|
||||
#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
|
||||
#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 || \
|
||||
XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
|
||||
|
@ -135,123 +177,56 @@
|
|||
#define IEEE_CTRL_ISOLATE_DISABLE 0xFBFF
|
||||
#endif
|
||||
|
||||
static int detect_phy(XEmacPs *xemacpsp)
|
||||
u32_t phymapemac0[32];
|
||||
u32_t phymapemac1[32];
|
||||
|
||||
static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr);
|
||||
static void SetUpSLCRDivisors(s32_t mac_baseaddr, s32_t speed);
|
||||
static u32_t configure_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr, u32_t speed);
|
||||
|
||||
#ifdef PCM_PMA_CORE_PRESENT
|
||||
u32_t phy_setup (XEmacPs *xemacpsp, u32_t phy_addr)
|
||||
{
|
||||
u16 phy_reg;
|
||||
u32 phy_addr;
|
||||
u32_t link_speed;
|
||||
u16_t regval;
|
||||
|
||||
for (phy_addr = 31; phy_addr > 0; phy_addr--) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG,
|
||||
&phy_reg);
|
||||
link_speed = get_IEEE_phy_speed(xemacpsp, phy_addr);
|
||||
if (link_speed == 1000)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
|
||||
else if (link_speed == 100)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
|
||||
else
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
|
||||
|
||||
if ((phy_reg != 0xFFFF) &&
|
||||
((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
|
||||
/* Found a valid PHY address */
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
|
||||
phy_addr));
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected.\r\n"));
|
||||
return phy_addr;
|
||||
}
|
||||
}
|
||||
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: No PHY detected. Assuming a PHY at address 0\r\n"));
|
||||
|
||||
/* default to zero */
|
||||
return 0;
|
||||
xil_printf("link speed for phy address %d: %d\r\n", phy_addr, link_speed);
|
||||
return link_speed;
|
||||
}
|
||||
|
||||
unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp)
|
||||
static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
|
||||
{
|
||||
u16 temp;
|
||||
u16 control;
|
||||
u16 status;
|
||||
u16 partner_capabilities;
|
||||
#ifdef XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT
|
||||
u32 phy_addr = XPAR_PCSPMA_1000BASEX_PHYADDR;
|
||||
#elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT
|
||||
u32 phy_addr = XPAR_PCSPMA_SGMII_PHYADDR;
|
||||
#elif XPAR_XEMACPS_0_BASEADDR
|
||||
u32 phy_addr = detect_phy(xemacpsp);
|
||||
#endif
|
||||
u16_t temp;
|
||||
u16_t control;
|
||||
u16_t status;
|
||||
u16_t partner_capabilities;
|
||||
|
||||
xil_printf("Start PHY autonegotiation \r\n");
|
||||
|
||||
#ifdef PCM_PMA_CORE_PRESENT
|
||||
#else
|
||||
XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
|
||||
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
|
||||
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
|
||||
control |= IEEE_PAUSE_MASK;
|
||||
control |= ADVERTISE_100;
|
||||
control |= ADVERTISE_10;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
&control);
|
||||
control |= ADVERTISE_1000;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
|
||||
&control);
|
||||
control |= (7 << 12); /* max number of gigabit attempts */
|
||||
control |= (1 << 11); /* enable downshift */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
|
||||
control);
|
||||
#endif
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
|
||||
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
|
||||
#ifdef PCM_PMA_CORE_PRESENT
|
||||
control &= IEEE_CTRL_ISOLATE_DISABLE;
|
||||
#endif
|
||||
control &= IEEE_CTRL_ISOLATE_DISABLE;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
#ifdef PCM_PMA_CORE_PRESENT
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control |= IEEE_CTRL_RESET_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
while (1) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
if (control & IEEE_CTRL_RESET_MASK)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
|
||||
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
|
||||
sleep(1);
|
||||
#ifdef PCM_PMA_CORE_PRESENT
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2,
|
||||
&temp);
|
||||
if (temp & IEEE_AUTONEG_ERROR_MASK) {
|
||||
xil_printf("Auto negotiation error \r\n");
|
||||
}
|
||||
#endif
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
|
||||
&status);
|
||||
}
|
||||
|
||||
}
|
||||
xil_printf("autonegotiation complete \r\n");
|
||||
|
||||
#ifdef PCM_PMA_CORE_PRESENT
|
||||
#else
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &partner_capabilities);
|
||||
#endif
|
||||
|
||||
#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 1);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &temp);
|
||||
|
@ -284,151 +259,57 @@ unsigned get_IEEE_phy_speed(XEmacPs *xemacpsp)
|
|||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, 0x0100);
|
||||
return 10;
|
||||
}
|
||||
#else
|
||||
if ( ((partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */
|
||||
return 1000;
|
||||
else if ( ((partner_capabilities >> 14) & 3) == 1)/* 100Mbps */
|
||||
return 100;
|
||||
else /* 10Mbps */
|
||||
return 10;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
unsigned configure_IEEE_phy_speed(XEmacPs *xemacpsp, unsigned speed)
|
||||
#else /*PCM_PMA_CORE_PRESENT not defined, GMII/RGMII case*/
|
||||
void detect_phy(XEmacPs *xemacpsp)
|
||||
{
|
||||
u16 control;
|
||||
u32 phy_addr = detect_phy(xemacpsp);
|
||||
u16_t phy_reg;
|
||||
u32_t phy_addr;
|
||||
u32_t emacnum;
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
|
||||
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
|
||||
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR)
|
||||
emacnum = 0;
|
||||
else
|
||||
emacnum = 1;
|
||||
for (phy_addr = 31; phy_addr > 0; phy_addr--) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG,
|
||||
&phy_reg);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
|
||||
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
|
||||
control |= IEEE_PAUSE_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, 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;
|
||||
if ((phy_reg != 0xFFFF) &&
|
||||
((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
|
||||
/* Found a valid PHY address */
|
||||
LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
|
||||
phy_addr));
|
||||
if (emacnum == 0)
|
||||
phymapemac0[phy_addr] = TRUE;
|
||||
else
|
||||
phymapemac1[phy_addr] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
else if (speed == 100) {
|
||||
control |= IEEE_CTRL_LINKSPEED_100M;
|
||||
/* Dont advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, 0);
|
||||
/* Dont advertise PHY speed of 10 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
|
||||
ADVERTISE_100);
|
||||
}
|
||||
|
||||
else if (speed == 10) {
|
||||
control |= IEEE_CTRL_LINKSPEED_10M;
|
||||
/* Dont advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
0);
|
||||
/* Dont advertise PHY speed of 100 Mbps */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG,
|
||||
ADVERTISE_10);
|
||||
}
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
|
||||
control | IEEE_CTRL_RESET_MASK);
|
||||
{
|
||||
volatile int wait;
|
||||
for (wait=0; wait < 100000; wait++);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SetUpSLCRDivisors(int mac_baseaddr, int speed)
|
||||
u32_t phy_setup (XEmacPs *xemacpsp, u32_t phy_addr)
|
||||
{
|
||||
volatile u32 slcrBaseAddress;
|
||||
u32 SlcrDiv0;
|
||||
u32 SlcrDiv1;
|
||||
u32 SlcrTxClkCntrl;
|
||||
|
||||
*(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
|
||||
|
||||
if (mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR;
|
||||
} else {
|
||||
slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR;
|
||||
}
|
||||
if (speed == 1000) {
|
||||
if (mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
} else if (speed == 100) {
|
||||
if (mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (mac_baseaddr == EMAC0_BASE_ADDRESS) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
SlcrTxClkCntrl = *(volatile unsigned int *)(slcrBaseAddress);
|
||||
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
|
||||
SlcrTxClkCntrl |= (SlcrDiv1 << 20);
|
||||
SlcrTxClkCntrl |= (SlcrDiv0 << 8);
|
||||
*(volatile unsigned int *)(slcrBaseAddress) = SlcrTxClkCntrl;
|
||||
*(volatile unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
unsigned Phy_Setup (XEmacPs *xemacpsp)
|
||||
{
|
||||
unsigned link_speed;
|
||||
unsigned short regval;
|
||||
unsigned long conv_present = 0;
|
||||
unsigned long convspeeddupsetting = 0;
|
||||
unsigned long convphyaddr = 0;
|
||||
u32_t link_speed;
|
||||
u16_t regval;
|
||||
u32_t conv_present = 0;
|
||||
u32_t convspeeddupsetting = 0;
|
||||
u32_t convphyaddr = 0;
|
||||
|
||||
#ifdef XPAR_GMII2RGMIICON_0N_ETH0_ADDR
|
||||
convphyaddr = XPAR_GMII2RGMIICON_0N_ETH0_ADDR;
|
||||
conv_present = 1;
|
||||
#else
|
||||
#endif
|
||||
#ifdef XPAR_GMII2RGMIICON_0N_ETH1_ADDR
|
||||
convphyaddr = XPAR_GMII2RGMIICON_0N_ETH1_ADDR;
|
||||
conv_present = 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_LINKSPEED_AUTODETECT
|
||||
link_speed = get_IEEE_phy_speed(xemacpsp);
|
||||
link_speed = get_IEEE_phy_speed(xemacpsp, phy_addr);
|
||||
if (link_speed == 1000) {
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
|
||||
|
@ -442,19 +323,19 @@ unsigned Phy_Setup (XEmacPs *xemacpsp)
|
|||
#elif defined(CONFIG_LINKSPEED1000)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
|
||||
link_speed = 1000;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
|
||||
sleep(1);
|
||||
#elif defined(CONFIG_LINKSPEED100)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
|
||||
link_speed = 100;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
|
||||
sleep(1);
|
||||
#elif defined(CONFIG_LINKSPEED10)
|
||||
SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
|
||||
link_speed = 10;
|
||||
configure_IEEE_phy_speed(xemacpsp, link_speed);
|
||||
configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
|
||||
convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
|
||||
sleep(1);
|
||||
#endif
|
||||
|
@ -463,6 +344,231 @@ unsigned Phy_Setup (XEmacPs *xemacpsp)
|
|||
XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting);
|
||||
}
|
||||
|
||||
xil_printf("link speed: %d\r\n", link_speed);
|
||||
xil_printf("link speed for phy address %d: %d\r\n", phy_addr, link_speed);
|
||||
return link_speed;
|
||||
}
|
||||
|
||||
static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
|
||||
{
|
||||
u16_t temp;
|
||||
u16_t control;
|
||||
u16_t status;
|
||||
u16_t partner_capabilities;
|
||||
|
||||
xil_printf("Start PHY autonegotiation \r\n");
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
|
||||
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
|
||||
control |= IEEE_ASYMMETRIC_PAUSE_MASK;
|
||||
control |= IEEE_PAUSE_MASK;
|
||||
control |= ADVERTISE_100;
|
||||
control |= ADVERTISE_10;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
&control);
|
||||
control |= ADVERTISE_1000;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
|
||||
control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
|
||||
&control);
|
||||
control |= (7 << 12); /* max number of gigabit attempts */
|
||||
control |= (1 << 11); /* enable downshift */
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
|
||||
control);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
|
||||
control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
control |= IEEE_CTRL_RESET_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
|
||||
|
||||
while (1) {
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
|
||||
if (control & IEEE_CTRL_RESET_MASK)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
|
||||
while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
|
||||
sleep(1);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_STATUS_REG_2,
|
||||
&temp);
|
||||
if (temp & IEEE_AUTONEG_ERROR_MASK) {
|
||||
xil_printf("Auto negotiation error \r\n");
|
||||
}
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
|
||||
&status);
|
||||
}
|
||||
xil_printf("autonegotiation complete \r\n");
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_SPECIFIC_STATUS_REG, &partner_capabilities);
|
||||
|
||||
if ( ((partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */
|
||||
return 1000;
|
||||
else if ( ((partner_capabilities >> 14) & 3) == 1)/* 100Mbps */
|
||||
return 100;
|
||||
else /* 10Mbps */
|
||||
return 10;
|
||||
}
|
||||
|
||||
static u32_t configure_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr, u32_t speed)
|
||||
{
|
||||
u16_t control;
|
||||
u16_t autonereg;
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
|
||||
control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
|
||||
autonereg |= IEEE_ASYMMETRIC_PAUSE_MASK;
|
||||
autonereg |= IEEE_PAUSE_MASK;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
|
||||
|
||||
XEmacPs_PhyRead(xemacpsp, 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;
|
||||
|
||||
/* Dont advertise PHY speed of 100 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
|
||||
autonereg &= (~ADVERTISE_100);
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
|
||||
|
||||
/* Dont advertise PHY speed of 10 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
|
||||
autonereg &= (~ADVERTISE_10);
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
|
||||
|
||||
/* Advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
|
||||
autonereg |= ADVERTISE_1000;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
|
||||
}
|
||||
|
||||
else if (speed == 100) {
|
||||
control |= IEEE_CTRL_LINKSPEED_100M;
|
||||
|
||||
/* Dont advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
|
||||
autonereg &= (~ADVERTISE_1000);
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
|
||||
|
||||
/* Dont advertise PHY speed of 10 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
|
||||
autonereg &= (~ADVERTISE_10);
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
|
||||
|
||||
/* Advertise PHY speed of 100 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
|
||||
autonereg |= ADVERTISE_100;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
|
||||
}
|
||||
|
||||
else if (speed == 10) {
|
||||
control |= IEEE_CTRL_LINKSPEED_10M;
|
||||
|
||||
/* Dont advertise PHY speed of 1000 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
|
||||
autonereg &= (~ADVERTISE_1000);
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
|
||||
|
||||
/* Dont advertise PHY speed of 100 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
|
||||
autonereg &= (~ADVERTISE_100);
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
|
||||
|
||||
/* Advertise PHY speed of 10 Mbps */
|
||||
XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
|
||||
autonereg |= ADVERTISE_10;
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
|
||||
}
|
||||
|
||||
XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
|
||||
control | IEEE_CTRL_RESET_MASK);
|
||||
{
|
||||
volatile s32_t wait;
|
||||
for (wait=0; wait < 100000; wait++);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /*PCM_PMA_CORE_PRESENT*/
|
||||
|
||||
static void SetUpSLCRDivisors(s32_t mac_baseaddr, s32_t speed)
|
||||
{
|
||||
volatile u32_t slcrBaseAddress;
|
||||
u32_t SlcrDiv0;
|
||||
u32_t SlcrDiv1;
|
||||
u32_t SlcrTxClkCntrl;
|
||||
|
||||
*(volatile u32_t *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
|
||||
|
||||
if (mac_baseaddr == XPAR_XEMACPS_0_BASEADDR) {
|
||||
slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR;
|
||||
} else {
|
||||
slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR;
|
||||
}
|
||||
if (speed == 1000) {
|
||||
if (mac_baseaddr == XPAR_XEMACPS_0_BASEADDR) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
} else if (speed == 100) {
|
||||
if (mac_baseaddr == XPAR_XEMACPS_0_BASEADDR) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
if (mac_baseaddr == XPAR_XEMACPS_0_BASEADDR) {
|
||||
#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
|
||||
SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
|
||||
SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
SlcrTxClkCntrl = *(volatile u32_t *)(slcrBaseAddress);
|
||||
SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
|
||||
SlcrTxClkCntrl |= (SlcrDiv1 << 20);
|
||||
SlcrTxClkCntrl |= (SlcrDiv0 << 8);
|
||||
*(volatile u32_t *)(slcrBaseAddress) = SlcrTxClkCntrl;
|
||||
*(volatile u32_t *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -44,9 +44,6 @@
|
|||
#include "arch/cc.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
/*** IMPORTANT: Define PEEP in xemacpsif.h and sys_arch_raw.c
|
||||
*** to run it on a PEEP board
|
||||
***/
|
||||
/*
|
||||
* This optional function does a "fast" critical region protection and returns
|
||||
* the previous protection level. This function is only called during very short
|
||||
|
@ -70,12 +67,8 @@ sys_arch_protect()
|
|||
cur = mfmsr();
|
||||
mtmsr(cur & ~XEXC_ALL);
|
||||
#elif __arm__
|
||||
#ifdef PEEP
|
||||
EmacDisableIntr();
|
||||
#else
|
||||
cur = mfcpsr();
|
||||
mtcpsr(cur | 0xC0);
|
||||
#endif
|
||||
#endif
|
||||
return cur;
|
||||
}
|
||||
|
@ -90,11 +83,7 @@ void
|
|||
sys_arch_unprotect(sys_prot_t lev)
|
||||
{
|
||||
#ifdef __arm__
|
||||
#ifdef PEEP
|
||||
EmacEnableIntr();
|
||||
#else
|
||||
mtcpsr(lev);
|
||||
#endif
|
||||
#else
|
||||
mtmsr(lev);
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue