* @rxd: Space for receiving SPI data, in DMA-able space.
  * @txd: Space for transmitting SPI data, in DMA-able space.
  * @msg_enable: The message flags controlling driver output (see ethtool).
+ * @tx_space: Free space in the hardware TX buffer (cached copy of KS_TXMIR).
+ * @queued_len: Space required in hardware TX buffer for queued packets in txq.
  * @fid: Incrementing frame id tag.
  * @rc_ier: Cached copy of KS_IER.
  * @rc_ccr: Cached copy of KS_CCR.
        struct work_struct      rxctrl_work;
 
        struct sk_buff_head     txq;
+       unsigned int            queued_len;
 
        struct eeprom_93cx6     eeprom;
        struct regulator        *vdd_reg;
 
                handled |= IRQ_RXPSI;
 
        if (status & IRQ_TXI) {
-               handled |= IRQ_TXI;
+               unsigned short tx_space = ks8851_rdreg16(ks, KS_TXMIR);
 
-               /* no lock here, tx queue should have been stopped */
+               netif_dbg(ks, intr, ks->netdev,
+                         "%s: txspace %d\n", __func__, tx_space);
 
-               /* update our idea of how much tx space is available to the
-                * system */
-               ks->tx_space = ks8851_rdreg16(ks, KS_TXMIR);
+               spin_lock(&ks->statelock);
+               ks->tx_space = tx_space;
+               if (netif_queue_stopped(ks->netdev))
+                       netif_wake_queue(ks->netdev);
+               spin_unlock(&ks->statelock);
 
-               netif_dbg(ks, intr, ks->netdev,
-                         "%s: txspace %d\n", __func__, ks->tx_space);
+               handled |= IRQ_TXI;
        }
 
        if (status & IRQ_RXI)
        if (status & IRQ_LCI)
                mii_check_link(&ks->mii);
 
-       if (status & IRQ_TXI)
-               netif_wake_queue(ks->netdev);
-
        return IRQ_HANDLED;
 }
 
        ks8851_wrreg16(ks, KS_ISR, ks->rc_ier);
        ks8851_wrreg16(ks, KS_IER, ks->rc_ier);
 
+       ks->queued_len = 0;
        netif_start_queue(ks->netdev);
 
        netif_dbg(ks, ifup, ks->netdev, "network device up\n");
 
                netdev_err(ks->netdev, "%s: spi_sync() failed\n", __func__);
 }
 
+/**
+ * calc_txlen - calculate size of message to send packet
+ * @len: Length of data
+ *
+ * Returns the size of the TXFIFO message needed to send
+ * this packet.
+ */
+static unsigned int calc_txlen(unsigned int len)
+{
+       return ALIGN(len + 4, 4);
+}
+
 /**
  * ks8851_rx_skb_spi - receive skbuff
  * @ks: The device state
  */
 static void ks8851_tx_work(struct work_struct *work)
 {
+       unsigned int dequeued_len = 0;
        struct ks8851_net_spi *kss;
+       unsigned short tx_space;
        struct ks8851_net *ks;
        unsigned long flags;
        struct sk_buff *txb;
                last = skb_queue_empty(&ks->txq);
 
                if (txb) {
+                       dequeued_len += calc_txlen(txb->len);
+
                        ks8851_wrreg16_spi(ks, KS_RXQCR,
                                           ks->rc_rxqcr | RXQCR_SDA);
                        ks8851_wrfifo_spi(ks, txb, last);
                }
        }
 
+       tx_space = ks8851_rdreg16_spi(ks, KS_TXMIR);
+
+       spin_lock(&ks->statelock);
+       ks->queued_len -= dequeued_len;
+       ks->tx_space = tx_space;
+       spin_unlock(&ks->statelock);
+
        ks8851_unlock_spi(ks, &flags);
 }
 
        flush_work(&kss->tx_work);
 }
 
-/**
- * calc_txlen - calculate size of message to send packet
- * @len: Length of data
- *
- * Returns the size of the TXFIFO message needed to send
- * this packet.
- */
-static unsigned int calc_txlen(unsigned int len)
-{
-       return ALIGN(len + 4, 4);
-}
-
 /**
  * ks8851_start_xmit_spi - transmit packet using SPI
  * @skb: The buffer to transmit
 
        spin_lock(&ks->statelock);
 
-       if (needed > ks->tx_space) {
+       if (ks->queued_len + needed > ks->tx_space) {
                netif_stop_queue(dev);
                ret = NETDEV_TX_BUSY;
        } else {
-               ks->tx_space -= needed;
+               ks->queued_len += needed;
                skb_queue_tail(&ks->txq, skb);
        }
 
        spin_unlock(&ks->statelock);
-       schedule_work(&kss->tx_work);
+       if (ret == NETDEV_TX_OK)
+               schedule_work(&kss->tx_work);
 
        return ret;
 }