Skip to content

Commit

Permalink
[PATCH] skge: use NAPI for transmit complete
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stephen Hemminger authored and Jeff Garzik committed Sep 6, 2006
1 parent 29365c9 commit 513f533
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 55 deletions.
82 changes: 28 additions & 54 deletions drivers/net/skge.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2432,27 +2418,27 @@ 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);
td->control = 0;
}

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)
Expand All @@ -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)
Expand Down Expand Up @@ -2679,15 +2665,15 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
}

/* 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;

Expand All @@ -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)
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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]);
}

Expand All @@ -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]);
}

Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down
1 change: 0 additions & 1 deletion drivers/net/skge.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 513f533

Please sign in to comment.