Big restructuring of TX logic

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1578 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2009-03-08 19:00:28 +00:00
parent e3fb74656d
commit 980c892b63

View File

@ -112,24 +112,31 @@
#endif
#if CONFIG_EZ80_PKTBUFSIZE == 256
# define EMAC_BUFSZ EMAC_BUFSZ_256b
# define EMAC_BUFSZ EMAC_BUFSZ_256b
# define EMAC_PKTBUF_SHIFT 8
#elif CONFIG_EZ80_PKTBUFSIZE == 128
# define EMAC_BUFSZ EMAC_BUFSZ_128b
# define EMAC_BUFSZ EMAC_BUFSZ_128b
# define EMAC_PKTBUF_SHIFT 7
#elif CONFIG_EZ80_PKTBUFSIZE == 64
# define EMAC_BUFSZ EMAC_BUFSZ_64b
# define EMAC_BUFSZ EMAC_BUFSZ_64b
# define EMAC_PKTBUF_SHIFT 6
#elif CONFIG_EZ80_PKTBUFSIZE == 32
# define EMAC_BUFSZ EMAC_BUFSZ_32b
# define EMAC_BUFSZ EMAC_BUFSZ_32b
# define EMAC_PKTBUF_SHIFT 5
#else
# error "Unsupported CONFIG_EZ80_PKTBUFSIZE value"
#endif
#define EMAC_PKTBUF_MASK (CONFIG_EZ80_PKTBUFSIZE - 1)
#define EMAC_PKTBUF_ALIGN(a) (((a) + EMAC_PKTBUF_MASK - 1) & ~EMAC_PKTBUF_MASK)
/* Am79c874 PHY configuration */
#define EZ80_EMAC_AUTONEG 0
#define EZ80_EMAC_100BFD 1
#define EZ80_EMAC_100BHD 2
#define EZ80_EMAC_10BFD 3
#define EZ80_EMAC_10BHD 4
#define EZ80_EMAC_AUTONEG 0
#define EZ80_EMAC_100BFD 1
#define EZ80_EMAC_100BHD 2
#define EZ80_EMAC_10BFD 3
#define EZ80_EMAC_10BHD 4
#ifndef CONFIG_EZ80_PHYCONFIG
# define CONFIG_EZ80_PHYCONFIG EZ80_EMAC_10BFD
@ -269,8 +276,6 @@ struct ez80emac_driver_s
* by ez80emac_transmit() when Tx is started and by ez80emac_reclaimtxdesc()
* when Tx processing completes. txhead == NULL is also a sure
* indication that there is no Tx in progress.
* txtail: Points to the last Tx descriptor queued for output. Initialized
* to NULL. Set by ez80emac_transmit() when a new Tx descriptor is added.
* txnext: Points to the next free Tx descriptor. Initialized to txstart; set
* when ez80emac_transmit() adds the descriptor; reset to txstart when the
* last Tx packet is sent.
@ -278,7 +283,6 @@ struct ez80emac_driver_s
FAR struct ez80emac_desc_s *txstart;
FAR struct ez80emac_desc_s *txhead;
FAR struct ez80emac_desc_s *txtail;
FAR struct ez80emac_desc_s *txnext;
/* Rx buffer management
@ -335,7 +339,7 @@ static void ez80emac_miiwrite(FAR struct ez80emac_driver_s *priv, ubyte offse
static uint16 ez80emac_miiread(FAR struct ez80emac_driver_s *priv, uint32 offset);
static boolean ez80emac_miipoll(FAR struct ez80emac_driver_s *priv, uint32 offset,
uint16 bits, boolean bclear);
static int ez80emac_miiautonegotiate(FAR struct ez80emac_driver_s *priv);
static int ez80emac_miiconfigure(FAR struct ez80emac_driver_s *priv);
/* Multi-cast filtering */
@ -522,7 +526,7 @@ static boolean ez80emac_miipoll(FAR struct ez80emac_driver_s *priv, uint32 offse
}
/****************************************************************************
* Function: ez80emac_miiautonegotiate
* Function: ez80emac_miiconfigure
*
* Description:
* Dump all MII registers
@ -540,7 +544,7 @@ static boolean ez80emac_miipoll(FAR struct ez80emac_driver_s *priv, uint32 offse
****************************************************************************/
#ifdef CONFIG_EZ80_PHYAM79C874
static int ez80emac_miiautonegotiate(FAR struct ez80emac_driver_s *priv)
static int ez80emac_miiconfigure(FAR struct ez80emac_driver_s *priv)
{
uint16 phyval;
boolean bauto;
@ -688,7 +692,7 @@ dumpregs:
return ret;
}
#else
static int ez80emac_miiautonegotiate(FAR struct ez80emac_driver_s *priv)
static int ez80emac_miiconfigure(FAR struct ez80emac_driver_s *priv)
{
uint16 advertise;
uint16 lpa;
@ -924,73 +928,98 @@ static void ez80emac_machash(FAR ubyte *mac, int *ndx, int *bitno)
static int ez80emac_transmit(struct ez80emac_driver_s *priv)
{
FAR struct ez80emac_desc_s *txdesc;
FAR struct ez80emac_desc_s *txnext;
ubyte *psrc;
ubyte *pdest;
uint24 len;
irqstate_t flags;
ubyte regval;
ubyte regval;
nvdbg("ENTRY: txnext=%p {%06x, %u, %04x} trp=%02x%02x\n",
priv->txnext, priv->txnext->np, priv->txnext->pktsize, priv->txnext->stat,
inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L));
/* Increment statistics */
flags = irqsave();
EMAC_STAT(priv, tx_queued);
/* Copy the data to the next packet in the Tx buffer */
flags = irqsave();
txdesc = priv->txnext;
txdesc->np = 0;
txdesc->pktsize = priv->dev.d_len;
txdesc->stat = 0;
memcpy((ubyte*)txdesc + SIZEOF_EMACSDESC, priv->dev.d_buf, priv->dev.d_len);
/* Add the new Tx descriptor to the tail of the chain. Is there a
* descriptor queued before this one?
/* The current packet to be sent is txnetx; Calculate the new txnext and
* set the ownership to host so that the EMAC does not try to transmit
* the next packet.
*
* The new txnext will be the current txnext plus the size of the descriptor
* header plus the size of the data to be transferred, aligned up to the next
* packet buffer size. NOTE: that there is no check to see if we have
* overran the EMAC buffer -- i.e., if the next txnext has not yet been
* tranmitted.
*/
if (priv->txtail)
{
/* Yes, link it to this one */
txdesc = priv->txnext;
len = EMAC_PKTBUF_ALIGN(priv->dev.d_len + SIZEOF_EMACSDESC);
txnext = (FAR struct ez80emac_desc_s *)((ubyte*)txdesc + len);
/* Handle wraparound to the beginning of the TX region */
priv->txtail->np = (uint24)txdesc;
if ((ubyte*)txnext + SIZEOF_EMACSDESC >= (ubyte*)priv->rxstart)
{
txnext = (FAR struct ez80emac_desc_s *)
((ubyte*)priv->txstart + ((ubyte*)txnext - (ubyte*)priv->rxstart));
}
priv->txnext = txnext;
txnext->np = 0;
txnext->pktsize = 0;
txnext->stat = 0; /* Bit 15: 0=Host (eZ80 CPU) owns, 1=EMAC owns. */
/* Copy the data to the next packet in the Tx buffer (handling wraparound) */
psrc = priv->dev.d_buf;
pdest = (ubyte*)txdesc + SIZEOF_EMACSDESC;
len = (ubyte*)priv->rxstart - pdest;
if (len >= priv->dev.d_len)
{
/* The entire packet will fit into the EMAC SRAM without wrapping */
memcpy(pdest, psrc, priv->dev.d_len);
}
else
{
/* No.. then there are no pending Tx actions. This
* descriptor is both the new head and tail.
*/
/* Handle wrap to the beginning of the buffer */
memcpy(pdest, psrc, len);
memcpy(priv->txstart, &psrc[len], (priv->dev.d_len - len));
}
if (!priv->txhead)
{
/* There are no pending TX actions. This descriptor is the new head */
priv->txhead = txdesc;
}
/* In any event, this descriptor is the new tail */
priv->txtail = txdesc;
/* Caculate the address of the next, available Tx descriptor.
* Hmmm... need some way to determine if the next descriptor
* is in use or not.
*/
priv->txnext = (FAR struct ez80emac_desc_s *)
((FAR ubyte*)txdesc + txdesc->pktsize + SIZEOF_EMACSDESC);
if (priv->txnext >= priv->rxstart)
{
priv->txnext = priv->txstart;
}
/* Setup the new 'next' Tx descriptor (very dangerous with
* no check for overrun!)
*/
priv->txnext->np = 0;
priv->txnext->pktsize = 0;
priv->txnext->stat = 0;
/* Then, give ownership of the descriptor to the hardware. It should
* perform the transmission on its next polling cycle.
*/
txdesc->np = (uint24)priv->txnext;
txdesc->stat = EMAC_TXDESC_OWNER;
txdesc->np = (uint24)priv->txnext;
txdesc->pktsize = priv->dev.d_len;
txdesc->stat = EMAC_TXDESC_OWNER;
/* Enable the TX poll timer. The poll timer may alread be running. In that
* case, this will force the hardware to poll again now
*/
outp(EZ80_EMAC_PTMR, EMAC_PTMR);
irqrestore(flags);
nvdbg("EXIT: txdesc=%p {%06x, %u, %04x}\n",
txdesc, txdesc->np, txdesc->pktsize, txdesc->stat);
nvdbg(" txnext=%p {%06x, %u, %04x} trp=%02x%02x\n",
txnext, txnext->np, txnext->pktsize, txnext->stat,
inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L));
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
(void)wd_start(priv->txtimeout, EMAC_TXTIMEOUT, ez80emac_txtimeout, 1, (uint32)priv);
@ -1021,26 +1050,24 @@ static int ez80emac_transmit(struct ez80emac_driver_s *priv)
static int ez80emac_uiptxpoll(struct uip_driver_s *dev)
{
struct ez80emac_driver_s *priv = (struct ez80emac_driver_s *)dev->d_private;
int ret = 0;
/* If the polling resulted in data that should be sent out on the network,
* the field d_len is set to a value > 0.
*/
nvdbg("Poll result: d_len=%d\n", priv->dev.d_len);
if (priv->dev.d_len > 0)
{
uip_arp_out(&priv->dev);
ez80emac_transmit(priv);
/* Check if there is room in the DM90x0 to hold another packet. If not,
* return a non-zero value to terminate the poll.
*/
ret = ez80emac_transmit(priv);
}
/* If zero is returned, the polling will continue until all connections have
* been examined.
*/
return 0;
return ret;
}
/****************************************************************************
@ -1113,10 +1140,14 @@ static int ez80emac_txinterrupt(int irq, FAR void *context)
priv->txhead = (FAR struct ez80emac_desc_s *)txdesc->np;
if (!priv->txhead)
{
/* If there is no new head, then there is no tail either */
/* No pending TX -- This should never happen because there
* is always a dummy descriptor at the end of the list owned
* by the host. Reset to the beginining of the buffer
* and stop the poll timer
*/
outp(EZ80_EMAC_PTMR, 0);
priv->txnext = priv->txstart;
priv->txtail = NULL;
/* Reset the transmit function. That should force the TRP to be
* the same as TDLP which is the set to txstart.
@ -1142,6 +1173,7 @@ static int ez80emac_txinterrupt(int irq, FAR void *context)
nvdbg("New txhead=%p {%06x, %u, %04x} trp=%02x%02x istat=%02x\n",
priv->txhead, priv->txhead->np, priv->txhead->pktsize, priv->txhead->stat,
inp(EZ80_EMAC_TRP_H), inp(EZ80_EMAC_TRP_L), istat);
return OK;
}
@ -1442,9 +1474,7 @@ static void ez80emac_polltimer(int argc, uint32 arg, ...)
{
struct ez80emac_driver_s *priv = (struct ez80emac_driver_s *)arg;
/* Check if there is room in the send another TXr packet. */
/* If so, update TCP timing states and poll uIP for new XMIT data */
/* Poll uIP for new XMIT data */
(void)uip_timer(&priv->dev, ez80emac_uiptxpoll, EMAC_POLLHSEC);
@ -1486,7 +1516,6 @@ static int ez80emac_ifup(FAR struct uip_driver_s *dev)
/* Bring up the interface -- Must be down right now */
DEBUGASSERT((inp(EZ80_EMAC_PTMR) == 0));
DEBUGASSERT((inp(EZ80_EMAC_CFG4) & EMAC_CFG4_RXEN) == 0);
/* Reset hardware */
@ -1530,10 +1559,6 @@ static int ez80emac_ifup(FAR struct uip_driver_s *dev)
regval |= EMAC_CFG4_RXEN;
outp(EZ80_EMAC_CFG4, regval);
/* Enable the Tx poll timer */
outp(EZ80_EMAC_PTMR, EMAC_PTMR);
/* Turn on interrupts */
outp(EZ80_EMAC_ISTAT, 0xff); /* Clear all pending interrupts */
@ -1543,7 +1568,7 @@ static int ez80emac_ifup(FAR struct uip_driver_s *dev)
(void)wd_start(priv->txpoll, EMAC_WDDELAY, ez80emac_polltimer, 1, (uint32)priv);
/* Enable the Ethernet interrupt */
/* Enable the Ethernet interrupts */
priv->bifup = TRUE;
up_enable_irq(EZ80_EMACRX_IRQ);
@ -1697,7 +1722,6 @@ static int ez80_emacinitialize(void)
priv->txstart = (FAR struct ez80emac_desc_s *)(addr);
priv->txnext = priv->txstart;
priv->txhead = NULL;
priv->txtail = NULL;
priv->txnext->np = 0;
priv->txnext->pktsize = 0;
@ -1848,9 +1872,9 @@ static int ez80_emacinitialize(void)
goto errout;
}
/* Set auto-negotion */
/* Configure the PHY */
ret = ez80emac_miiautonegotiate(priv);
ret = ez80emac_miiconfigure(priv);
/* Initialize DMA / FIFO */
@ -2021,7 +2045,6 @@ void up_netuninitialize(void)
priv->txnext = priv->txstart;
priv->txhead = NULL;
priv->txtail = NULL;
irq_detach(EZ80_EMACRX_IRQ);
irq_detach(EZ80_EMACTX_IRQ);