Commit d080cd63 authored by Dai Haruki's avatar Dai Haruki Committed by Jeff Garzik

gianfar: Support NAPI for TX Frames

Poll the completed TX frames in gfar_poll().  This prevents the tx
completion interrupt from interfering with processing of received
frames.

We also disable hardware rx coalescing when NAPI is enabled.
Signed-off-by: default avatarDai Haruki <dai.haruki@freescale.com>
Signed-off-by: default avatarAndy Fleming <afleming@freescale.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 0b50d753
...@@ -1250,17 +1250,12 @@ static void gfar_timeout(struct net_device *dev) ...@@ -1250,17 +1250,12 @@ static void gfar_timeout(struct net_device *dev)
} }
/* Interrupt Handler for Transmit complete */ /* Interrupt Handler for Transmit complete */
static irqreturn_t gfar_transmit(int irq, void *dev_id) int gfar_clean_tx_ring(struct net_device *dev)
{ {
struct net_device *dev = (struct net_device *) dev_id;
struct gfar_private *priv = netdev_priv(dev);
struct txbd8 *bdp; struct txbd8 *bdp;
struct gfar_private *priv = netdev_priv(dev);
int howmany = 0;
/* Clear IEVENT */
gfar_write(&priv->regs->ievent, IEVENT_TX_MASK);
/* Lock priv */
spin_lock(&priv->txlock);
bdp = priv->dirty_tx; bdp = priv->dirty_tx;
while ((bdp->status & TXBD_READY) == 0) { while ((bdp->status & TXBD_READY) == 0) {
/* If dirty_tx and cur_tx are the same, then either the */ /* If dirty_tx and cur_tx are the same, then either the */
...@@ -1269,7 +1264,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) ...@@ -1269,7 +1264,7 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id)
if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0))
break; break;
dev->stats.tx_packets++; howmany++;
/* Deferred means some collisions occurred during transmit, */ /* Deferred means some collisions occurred during transmit, */
/* but we eventually sent the packet. */ /* but we eventually sent the packet. */
...@@ -1278,11 +1273,15 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) ...@@ -1278,11 +1273,15 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id)
/* Free the sk buffer associated with this TxBD */ /* Free the sk buffer associated with this TxBD */
dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]);
priv->tx_skbuff[priv->skb_dirtytx] = NULL; priv->tx_skbuff[priv->skb_dirtytx] = NULL;
priv->skb_dirtytx = priv->skb_dirtytx =
(priv->skb_dirtytx + (priv->skb_dirtytx +
1) & TX_RING_MOD_MASK(priv->tx_ring_size); 1) & TX_RING_MOD_MASK(priv->tx_ring_size);
/* Clean BD length for empty detection */
bdp->length = 0;
/* update bdp to point at next bd in the ring (wrapping if necessary) */ /* update bdp to point at next bd in the ring (wrapping if necessary) */
if (bdp->status & TXBD_WRAP) if (bdp->status & TXBD_WRAP)
bdp = priv->tx_bd_base; bdp = priv->tx_bd_base;
...@@ -1297,6 +1296,25 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id) ...@@ -1297,6 +1296,25 @@ static irqreturn_t gfar_transmit(int irq, void *dev_id)
netif_wake_queue(dev); netif_wake_queue(dev);
} /* while ((bdp->status & TXBD_READY) == 0) */ } /* while ((bdp->status & TXBD_READY) == 0) */
dev->stats.tx_packets += howmany;
return howmany;
}
/* Interrupt Handler for Transmit complete */
static irqreturn_t gfar_transmit(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct gfar_private *priv = netdev_priv(dev);
/* Clear IEVENT */
gfar_write(&priv->regs->ievent, IEVENT_TX_MASK);
/* Lock priv */
spin_lock(&priv->txlock);
gfar_clean_tx_ring(dev);
/* If we are coalescing the interrupts, reset the timer */ /* If we are coalescing the interrupts, reset the timer */
/* Otherwise, clear it */ /* Otherwise, clear it */
if (likely(priv->txcoalescing)) { if (likely(priv->txcoalescing)) {
...@@ -1392,15 +1410,15 @@ irqreturn_t gfar_receive(int irq, void *dev_id) ...@@ -1392,15 +1410,15 @@ irqreturn_t gfar_receive(int irq, void *dev_id)
unsigned long flags; unsigned long flags;
#endif #endif
/* Clear IEVENT, so rx interrupt isn't called again
* because of this interrupt */
gfar_write(&priv->regs->ievent, IEVENT_RX_MASK);
/* support NAPI */ /* support NAPI */
#ifdef CONFIG_GFAR_NAPI #ifdef CONFIG_GFAR_NAPI
/* Clear IEVENT, so interrupts aren't called again
* because of the packets that have already arrived */
gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK);
if (netif_rx_schedule_prep(dev, &priv->napi)) { if (netif_rx_schedule_prep(dev, &priv->napi)) {
tempval = gfar_read(&priv->regs->imask); tempval = gfar_read(&priv->regs->imask);
tempval &= IMASK_RX_DISABLED; tempval &= IMASK_RTX_DISABLED;
gfar_write(&priv->regs->imask, tempval); gfar_write(&priv->regs->imask, tempval);
__netif_rx_schedule(dev, &priv->napi); __netif_rx_schedule(dev, &priv->napi);
...@@ -1411,6 +1429,9 @@ irqreturn_t gfar_receive(int irq, void *dev_id) ...@@ -1411,6 +1429,9 @@ irqreturn_t gfar_receive(int irq, void *dev_id)
gfar_read(&priv->regs->imask)); gfar_read(&priv->regs->imask));
} }
#else #else
/* Clear IEVENT, so rx interrupt isn't called again
* because of this interrupt */
gfar_write(&priv->regs->ievent, IEVENT_RX_MASK);
spin_lock_irqsave(&priv->rxlock, flags); spin_lock_irqsave(&priv->rxlock, flags);
gfar_clean_rx_ring(dev, priv->rx_ring_size); gfar_clean_rx_ring(dev, priv->rx_ring_size);
...@@ -1580,6 +1601,13 @@ static int gfar_poll(struct napi_struct *napi, int budget) ...@@ -1580,6 +1601,13 @@ static int gfar_poll(struct napi_struct *napi, int budget)
struct gfar_private *priv = container_of(napi, struct gfar_private, napi); struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
struct net_device *dev = priv->dev; struct net_device *dev = priv->dev;
int howmany; int howmany;
unsigned long flags;
/* If we fail to get the lock, don't bother with the TX BDs */
if (spin_trylock_irqsave(&priv->txlock, flags)) {
gfar_clean_tx_ring(dev);
spin_unlock_irqrestore(&priv->txlock, flags);
}
howmany = gfar_clean_rx_ring(dev, budget); howmany = gfar_clean_rx_ring(dev, budget);
......
...@@ -126,9 +126,16 @@ extern const char gfar_driver_version[]; ...@@ -126,9 +126,16 @@ extern const char gfar_driver_version[];
#define DEFAULT_TXCOUNT 16 #define DEFAULT_TXCOUNT 16
#define DEFAULT_TXTIME 21 #define DEFAULT_TXTIME 21
#define DEFAULT_RXTIME 21
/* Non NAPI Case */
#ifndef CONFIG_GFAR_NAPI
#define DEFAULT_RX_COALESCE 1 #define DEFAULT_RX_COALESCE 1
#define DEFAULT_RXCOUNT 16 #define DEFAULT_RXCOUNT 16
#define DEFAULT_RXTIME 21 #else
#define DEFAULT_RX_COALESCE 0
#define DEFAULT_RXCOUNT 0
#endif /* CONFIG_GFAR_NAPI */
#define TBIPA_VALUE 0x1f #define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007 #define MIIMCFG_INIT_VALUE 0x00000007
...@@ -242,6 +249,7 @@ extern const char gfar_driver_version[]; ...@@ -242,6 +249,7 @@ extern const char gfar_driver_version[];
#define IEVENT_PERR 0x00000001 #define IEVENT_PERR 0x00000001
#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0) #define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0)
#define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF) #define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF)
#define IEVENT_RTX_MASK (IEVENT_RX_MASK | IEVENT_TX_MASK)
#define IEVENT_ERR_MASK \ #define IEVENT_ERR_MASK \
(IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \ (IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \ IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
...@@ -269,11 +277,12 @@ extern const char gfar_driver_version[]; ...@@ -269,11 +277,12 @@ extern const char gfar_driver_version[];
#define IMASK_FIQ 0x00000004 #define IMASK_FIQ 0x00000004
#define IMASK_DPE 0x00000002 #define IMASK_DPE 0x00000002
#define IMASK_PERR 0x00000001 #define IMASK_PERR 0x00000001
#define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY)
#define IMASK_DEFAULT (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \ #define IMASK_DEFAULT (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \ IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \ IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
| IMASK_PERR) | IMASK_PERR)
#define IMASK_RTX_DISABLED ((~(IMASK_RXFEN0 | IMASK_TXFEN | IMASK_BSY)) \
& IMASK_DEFAULT)
/* Fifo management */ /* Fifo management */
#define FIFO_TX_THR_MASK 0x01ff #define FIFO_TX_THR_MASK 0x01ff
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment