diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-03-08 19:00:28 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-03-08 19:00:28 +0000 |
commit | c5c0cb02e491b41e050f830f5ab5f9cba6009461 (patch) | |
tree | 12ba97474d60fba09e6bade065020fd57d00383d /nuttx/arch/z80 | |
parent | 4e0cda19a741a8006d00e69428b46ea3379498ad (diff) | |
download | px4-nuttx-c5c0cb02e491b41e050f830f5ab5f9cba6009461.tar.gz px4-nuttx-c5c0cb02e491b41e050f830f5ab5f9cba6009461.tar.bz2 px4-nuttx-c5c0cb02e491b41e050f830f5ab5f9cba6009461.zip |
Big restructuring of TX logic
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1578 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/z80')
-rw-r--r-- | nuttx/arch/z80/src/ez80/ez80_emac.c | 177 |
1 files changed, 100 insertions, 77 deletions
diff --git a/nuttx/arch/z80/src/ez80/ez80_emac.c b/nuttx/arch/z80/src/ez80/ez80_emac.c index b920505d1..6d10d5bc5 100644 --- a/nuttx/arch/z80/src/ez80/ez80_emac.c +++ b/nuttx/arch/z80/src/ez80/ez80_emac.c @@ -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 */ + /* 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. + */ - 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); + 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 */ - /* Add the new Tx descriptor to the tail of the chain. Is there a - * descriptor queued before this one? - */ + 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. */ - if (priv->txtail) + /* 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) { - /* Yes, link it to this one */ + /* The entire packet will fit into the EMAC SRAM without wrapping */ - priv->txtail->np = (uint24)txdesc; + 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 */ - priv->txhead = txdesc; + memcpy(pdest, psrc, len); + memcpy(priv->txstart, &psrc[len], (priv->dev.d_len - len)); } - /* 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) + if (!priv->txhead) { - priv->txnext = priv->txstart; + /* There are no pending TX actions. This descriptor is the new head */ + + priv->txhead = txdesc; } - /* Setup the new 'next' Tx descriptor (very dangerous with - * no check for overrun!) + /* Then, give ownership of the descriptor to the hardware. It should + * perform the transmission on its next polling cycle. */ - priv->txnext->np = 0; - priv->txnext->pktsize = 0; - priv->txnext->stat = 0; + txdesc->np = (uint24)priv->txnext; + txdesc->pktsize = priv->dev.d_len; + txdesc->stat = EMAC_TXDESC_OWNER; - /* Then, give ownership of the descriptor to the hardware. It should - * perform the transmission on its next polling cycle. + /* Enable the TX poll timer. The poll timer may alread be running. In that + * case, this will force the hardware to poll again now */ - txdesc->np = (uint24)priv->txnext; - txdesc->stat = EMAC_TXDESC_OWNER; + 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); |