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
|