[PATCH] skge: use NAPI for transmit complete
authorStephen Hemminger <shemminger@osdl.org>
Fri, 1 Sep 2006 22:53:49 +0000 (15:53 -0700)
committerJeff Garzik <jeff@garzik.org>
Wed, 6 Sep 2006 15:19:23 +0000 (11:19 -0400)
The skge driver has much better performance if transmit done is handled in
NAPI softirq. Change from doing transmit locking in driver (LLTX) and
use device lock.

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/net/skge.c
drivers/net/skge.h

index 8a321be24835a96ad4e85cc810ffce1805c1fc11..34a4b87819bd8a750f1846cc2d9056eb890deff5 100644 (file)
@@ -91,7 +91,7 @@ MODULE_DEVICE_TABLE(pci, skge_id_table);
 static int skge_up(struct net_device *dev);
 static int skge_down(struct net_device *dev);
 static void skge_phy_reset(struct skge_port *skge);
-static void skge_tx_clean(struct skge_port *skge);
+static void skge_tx_clean(struct net_device *dev);
 static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
 static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
 static void genesis_get_stats(struct skge_port *skge, u64 *data);
@@ -105,6 +105,7 @@ static const int txqaddr[] = { Q_XA1, Q_XA2 };
 static const int rxqaddr[] = { Q_R1, Q_R2 };
 static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
 static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
+static const u32 irqmask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F };
 
 static int skge_get_regs_len(struct net_device *dev)
 {
@@ -2283,7 +2284,7 @@ static int skge_down(struct net_device *dev)
        skge_led(skge, LED_MODE_OFF);
 
        netif_poll_disable(dev);
-       skge_tx_clean(skge);
+       skge_tx_clean(dev);
        skge_rx_clean(skge);
 
        kfree(skge->rx_ring.start);
@@ -2308,25 +2309,12 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
        int i;
        u32 control, len;
        u64 map;
-       unsigned long flags;
 
        if (skb_padto(skb, ETH_ZLEN))
                return NETDEV_TX_OK;
 
-       if (!spin_trylock_irqsave(&skge->tx_lock, flags))
-               /* Collision - tell upper layer to requeue */
-               return NETDEV_TX_LOCKED;
-
-       if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1)) {
-               if (!netif_queue_stopped(dev)) {
-                       netif_stop_queue(dev);
-
-                       printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
-                              dev->name);
-               }
-               spin_unlock_irqrestore(&skge->tx_lock, flags);
+       if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1))
                return NETDEV_TX_BUSY;
-       }
 
        e = skge->tx_ring.to_use;
        td = e->desc;
@@ -2401,8 +2389,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        }
 
-       spin_unlock_irqrestore(&skge->tx_lock, flags);
-
        dev->trans_start = jiffies;
 
        return NETDEV_TX_OK;
@@ -2432,18 +2418,18 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
                        printk(KERN_DEBUG PFX "%s: tx done slot %td\n",
                               skge->netdev->name, e - skge->tx_ring.start);
 
-               dev_kfree_skb_any(e->skb);
+               dev_kfree_skb(e->skb);
        }
        e->skb = NULL;
 }
 
 /* Free all buffers in transmit ring */
-static void skge_tx_clean(struct skge_port *skge)
+static void skge_tx_clean(struct net_device *dev)
 {
+       struct skge_port *skge = netdev_priv(dev);
        struct skge_element *e;
-       unsigned long flags;
 
-       spin_lock_irqsave(&skge->tx_lock, flags);
+       netif_tx_lock_bh(dev);
        for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) {
                struct skge_tx_desc *td = e->desc;
                skge_tx_free(skge, e, td->control);
@@ -2451,8 +2437,8 @@ static void skge_tx_clean(struct skge_port *skge)
        }
 
        skge->tx_ring.to_clean = e;
-       netif_wake_queue(skge->netdev);
-       spin_unlock_irqrestore(&skge->tx_lock, flags);
+       netif_wake_queue(dev);
+       netif_tx_unlock_bh(dev);
 }
 
 static void skge_tx_timeout(struct net_device *dev)
@@ -2463,7 +2449,7 @@ static void skge_tx_timeout(struct net_device *dev)
                printk(KERN_DEBUG PFX "%s: tx timeout\n", dev->name);
 
        skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP);
-       skge_tx_clean(skge);
+       skge_tx_clean(dev);
 }
 
 static int skge_change_mtu(struct net_device *dev, int new_mtu)
@@ -2679,15 +2665,15 @@ resubmit:
 }
 
 /* Free all buffers in Tx ring which are no longer owned by device */
-static void skge_txirq(struct net_device *dev)
+static void skge_tx_done(struct net_device *dev)
 {
        struct skge_port *skge = netdev_priv(dev);
        struct skge_ring *ring = &skge->tx_ring;
        struct skge_element *e;
 
-       rmb();
+       skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
 
-       spin_lock(&skge->tx_lock);
+       netif_tx_lock(dev);
        for (e = ring->to_clean; e != ring->to_use; e = e->next) {
                struct skge_tx_desc *td = e->desc;
 
@@ -2698,11 +2684,10 @@ static void skge_txirq(struct net_device *dev)
        }
        skge->tx_ring.to_clean = e;
 
-       if (netif_queue_stopped(skge->netdev)
-           && skge_avail(&skge->tx_ring) > TX_LOW_WATER)
-               netif_wake_queue(skge->netdev);
+       if (skge_avail(&skge->tx_ring) > TX_LOW_WATER)
+               netif_wake_queue(dev);
 
-       spin_unlock(&skge->tx_lock);
+       netif_tx_unlock(dev);
 }
 
 static int skge_poll(struct net_device *dev, int *budget)
@@ -2714,6 +2699,10 @@ static int skge_poll(struct net_device *dev, int *budget)
        int to_do = min(dev->quota, *budget);
        int work_done = 0;
 
+       skge_tx_done(dev);
+
+       skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
+
        for (e = ring->to_clean; prefetch(e->next), work_done < to_do; e = e->next) {
                struct skge_rx_desc *rd = e->desc;
                struct sk_buff *skb;
@@ -2744,10 +2733,9 @@ static int skge_poll(struct net_device *dev, int *budget)
        if (work_done >=  to_do)
                return 1; /* not done */
 
-       netif_rx_complete(dev);
-
        spin_lock_irq(&hw->hw_lock);
-       hw->intr_mask |= rxirqmask[skge->port];
+       __netif_rx_complete(dev);
+       hw->intr_mask |= irqmask[skge->port];
        skge_write32(hw, B0_IMSK, hw->intr_mask);
        skge_read32(hw, B0_IMSK);
        spin_unlock_irq(&hw->hw_lock);
@@ -2906,14 +2894,8 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
                schedule_work(&hw->phy_work);
        }
 
-       if (status & IS_XA1_F) {
-               skge_write8(hw, Q_ADDR(Q_XA1, Q_CSR), CSR_IRQ_CL_F);
-               skge_txirq(hw->dev[0]);
-       }
-
-       if (status & IS_R1_F) {
-               skge_write8(hw, Q_ADDR(Q_R1, Q_CSR), CSR_IRQ_CL_F);
-               hw->intr_mask &= ~IS_R1_F;
+       if (status & (IS_XA1_F|IS_R1_F)) {
+               hw->intr_mask &= ~(IS_XA1_F|IS_R1_F);
                netif_rx_schedule(hw->dev[0]);
        }
 
@@ -2932,14 +2914,8 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
                skge_mac_intr(hw, 0);
 
        if (hw->dev[1]) {
-               if (status & IS_XA2_F) {
-                       skge_write8(hw, Q_ADDR(Q_XA2, Q_CSR), CSR_IRQ_CL_F);
-                       skge_txirq(hw->dev[1]);
-               }
-
-               if (status & IS_R2_F) {
-                       skge_write8(hw, Q_ADDR(Q_R2, Q_CSR), CSR_IRQ_CL_F);
-                       hw->intr_mask &= ~IS_R2_F;
+               if (status & (IS_XA2_F|IS_R2_F)) {
+                       hw->intr_mask &= ~(IS_XA2_F|IS_R2_F);
                        netif_rx_schedule(hw->dev[1]);
                }
 
@@ -3228,7 +3204,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
        dev->poll_controller = skge_netpoll;
 #endif
        dev->irq = hw->pdev->irq;
-       dev->features = NETIF_F_LLTX;
+
        if (highmem)
                dev->features |= NETIF_F_HIGHDMA;
 
@@ -3250,8 +3226,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
 
        skge->port = port;
 
-       spin_lock_init(&skge->tx_lock);
-
        if (hw->chip_id != CHIP_ID_GENESIS) {
                dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
                skge->rx_csum = 1;
index 593387b3c0dd039d9c44c33e29d5a471ce7769c6..79e09271bcf9b5e8f8d25553595b5d020e9e050c 100644 (file)
@@ -2417,7 +2417,6 @@ struct skge_port {
        struct net_device    *netdev;
        int                  port;
 
-       spinlock_t           tx_lock;
        struct skge_ring     tx_ring;
        struct skge_ring     rx_ring;