netdev
[Top] [All Lists]

Re: Tx queueing

To: jamal <hadi@xxxxxxxxxx>
Subject: Re: Tx queueing
From: Donald Becker <becker@xxxxxxxxx>
Date: Mon, 22 May 2000 18:54:37 -0400 (EDT)
Cc: "netdev@xxxxxxxxxxx" <netdev@xxxxxxxxxxx>
In-reply-to: <Pine.GSO.4.20.0005221156010.20167-100000@xxxxxxxxxxxxxxxx>
Sender: owner-netdev@xxxxxxxxxxx
On Mon, 22 May 2000, jamal wrote:

> On Sun, 21 May 2000, Jeff Garzik wrote:
> 
> > Example A:
> > 
> >     drv_start_xmit() {
> spinlock
> >             netif_stop_queue()
> >             /* queue packet for xmit */
> >             if (!tx_full)
> >                     netif_start_queue()
> >     }
> unlock
..
> that should do it; you are already doing it anyways.
> 
> I hope Donald doesnt flame me ;->

What a foolish, foolish hope.

There are some chips where the transmit routines don't need to be
locked against other activity such as the interrupt handler, only against
simultaneous entry of drv_start_xmit() by multiple processors.
Always having a spinlock adds overhead.

What we want for those chips is
      netif_block_tx(dev);      /* Block other func. entries on pre-2.3. */
...
      if (full) {
          np->tx_full = 1;
          netif_pause_tx(dev);
          /* We must later do netif_wake_queue()!! */
      } else
          netif_unblock_tx(dev);

To make it backward-compatible it would be
      netif_block_tx(dev, timeout_handler, timeout);
(C.f. David Hinds' vesion:  tx_timeout_check(dev, tx_timeout) ).

Or we could just insist that all netdrivers implement their own watchdogs.


Some driver *will* need to do
      netif_block_tx(dev);      /* Block other Tx entries. */
      spinlock(np->tx_window_spinlock);
      change_chip_state(ioaddr);
...
      change_chip_state_back(ioaddr);
      unlock(np->tx_window_spinlock);
      if (full)
          netif_pause_tx(dev);
      else
          netif_unblock_tx(dev);


________________
/* 2.3.43+ implicitly blocks simultaneous entry. */
#define netif_block_tx(dev)     do { } while (0)
#define netif_unblock_tx(dev)   do { } while (0)
#else
#define netif_block_tx(dev)     set_bit(0, (void *)&(dev)->tbusy)
#define netif_unblock_tx(dev)   clear_bit(0, (void *)&(dev)->tbusy)

   or

#define netif_block_tx(dev, timeout_handler, timeout) \
    do { if (test_and_set_bit(0, (void *)&(dev)->tbusy) != 0) { \
        if ((timeout_handler) == 0  || \
          jiffies - (dev)->trans_start < (timeout)) return 1; \
        else (timeout_handler)(dev); \
    } } while (0)
________________


Donald Becker                           becker@xxxxxxxxx
Scyld Computing Corporation
410 Severn Ave. Suite 210
Annapolis MD 21403



<Prev in Thread] Current Thread [Next in Thread>