[ECOS] "packets eaten" with AT91 EMAC Ethernet driver

Jürgen Lambrecht J.Lambrecht@televic.com
Tue Jun 10 16:11:00 GMT 2008


Lambrecht Jürgen wrote:
>   
>> -----Original Message-----
>> From: Andrew Lunn [mailto:andrew@lunn.ch]
>> Sent: maandag 9 juni 2008 17:32
>> To: Lambrecht Jürgen
>> Cc: ecos-discuss@ecos.sourceware.org; I-Yanaslov
>> Subject: Re: [ECOS] "packets eaten" with AT91 EMAC Ethernet driver
>>
>> On Mon, Jun 09, 2008 at 05:19:02PM +0200, J?rgen Lambrecht wrote:
>>     
>>> Hello,
>>>
>>> Since I solved the bugs in the AT91 EMAC driver
>>> (RX: reset of ?bytes_in_list? (position in current sg_list))(TX: at
>>> TXERR IRQ, reset SW pointer; set all used bits to 0 instead of 1),
>>> I always had the same problem: after a while of communicating over
>>> Ethernet with the AT91 EMAC, packets get ?eaten?.
>>>
>>> TX Packets get stuck, and they need an RX packet to get out.
>>>       
>> It sounds like missed interrupts, or a race condition in the interrupt
>> handling.
>>     
> Yes indeed.
> The original driver does not mask interrupts at the start of the ISR and unmask them at the end of the DSR.
> Is it correct that this mask/unmask is not needed because it is an internal interrupt and at the end of the ISR 'cyg_interrupt_acknowledge(vector)' is called - this acknowledge clears the interrupt? So this should be ok.
>
> Maybe there is a sort of race condition with can_send()?
>
>   
Indeed, that was the problem:
Wrong code in at91_eth_deliver():

   if (tsr&AT91_EMAC_TSR_COMP) //5
   {
      at91_reset_tbd(priv);
      _eth_drv_tx_done(sc,priv->curr_tx_key,0);
      priv->tx_busy = false;
   }

Correct code:
   {
      at91_reset_tbd(priv, b_reset_tbd_idx);
      priv->tx_busy = false;
      _eth_drv_tx_done(sc,priv->curr_tx_key,0);
   }

Aparantly very few people know how the complete TCP/IP stack works in 
eCos.... I also did not knew it, now I know:
The high-level TCP/IP stack puts al its data in a buffer, and calls once 
the "middleware" /io/eth/current/src/net/eth_drv.c::eth_drv_send() function.
If the low-level driver is available (can_send() returns not zero) then 
the first packet is sent.
If the low-level driver is not available it stops here. It is supposed 
that the low-level driver will inform then the middleware when it is 
ready by calling tx_done.
eth_drv_tx_done on its turn calls eth_drv_send() which then checks again 
can_send()

The AT91 driver first called tx_done, calling send calling can_send 
which returns 0 of course.
And afterwards - too late - busy is set to true, so that can_send can 
return 1...

Missing a TX interrupt is fatal..
Then the option CYGPKG_NET_FAST_THREAD_TICKLE_DEVS is very handy 
(default on option!)! But this unblocks only an already blocked driver..
Mark that for LW-IP and Redboot there are other drivers there.

Kind regards,
Jürgen

P.S.: my troubles are not yet finished; I have RX BNA problems now..



-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss



More information about the Ecos-discuss mailing list