Re: Stalls on sync PPP transmission (new card)

Henner Eisen (eis@baty.hanse.de)
14 Oct 1999 23:22:03 +0200


Hi,

>>>>> Linux Lists <lists@cyclades.com> writes:

>Ok, let's see if this e-mail provides more useful info. This is the
>skeleton of cpc_queue_xmit:
>
>static int cpc_queue_xmit(struct sk_buff *skb, struct device *dev)
>{
> if (dev->tbusy) {
> if (time_before(jiffies, dev->trans_start + PC300_TX_TIMEOUT))
> return 1;
>
> stats->tx_dropped++;
> dev->tbusy=0;
This should be followed by a mark_bh(NET_BH).

This code part is only reached when an xmit timeout condition is
detected (tbusy was set for a too long time, e.g. because a tx
interrupt got lost). This should be a rare case. If this occurs frequently,
then there is probably a bug. You might insert a printk() for debugging
purpose here as well in order to detect if this is reached too frequently.

> }
>
> if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
> return 1;
>
This kind of locking is legacy code (still present in lots of drivers,
it was necessary before linux 1.2.9, but strictly depraced now as it might
be subject to race conditions with linux 2.3.x multithreaded linux
network core).

Leave it out. tbusy should only be set in the dev->hard_start_xmit()
thread when an xmitter-busy condition is detected (in your driver, this
is probably at those location where your cpc_queue_xmit() returns 1).
Other threads (e.g. interrupt handlers) are only allowed to clear tbusy.

tbusy is only to tell the upper layer whether the device is willing to
accept more data for output. It should not be [ab]used for setting
driver-internal locking state.

>
> /* Write buffer to on-board DMA buffers */
> CPC_LOCK(card, flags);
> if(dma_buf_write(card, chan, (ucchar *)skb->data, skb->len) != 0) {
> CPC_UNLOCK(card, flags);
> stats->tx_dropped++;
> dev_kfree_skb(skb);
> return 1;
> }
> CPC_UNLOCK(card, flags);
>
> stats->tx_bytes += skb->len;
> dev_kfree_skb(skb);
> stats->tx_packets++;
> dev->trans_start = jiffies;
> dev->tbusy = 0;
> mark_bh(NET_BH);
>
> /* Start transmission */
> tx_dma_start(card, chan);
>
> return 0;
>}
>
>Note that mark_bh is called just after dev->tbusy is set to 0 (before you
>ask, there are no dropped packets, so I know that the other places where
>tbusy could be set to 0 are not reached).
>
>Furthermore, the only other places where the tbusy value is changed are
>the open (tbusy = 0) and close (tbusy = 1) functions.
>
Tbusy usually should be cleared whenever the driver detects that
the device has become ready to accept a new frame for transmission.
This usually occurs in the driverīs interrupt handler when it detects
that the last frame has successfully been send out because after that, the
device is usually willing to accept the next frame for transmission.
(some other code parts, e.g. error recovery and initialization routines, might
do so as well).

>Do you know of anything else that might cause this?? Do you have any
>suggestion on where to look (or what to use to debug it) in order to find
>the culprit??
>
>Thanks for your help.
>
>Regards,
>Ivan

Henner

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/