summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Fleming <afleming@freescale.com>2008-12-16 15:33:40 -0800
committerDavid S. Miller <davem@davemloft.net>2008-12-16 15:33:40 -0800
commit31de198b4d2732028f4c5bff04b0103b1d8c1d8c (patch)
tree63b971edc7f662d402769cfaf3c50465f3aab48d
parenta22823e72a4821ce1d4a248fbd8f5a81795af339 (diff)
downloadop-kernel-dev-31de198b4d2732028f4c5bff04b0103b1d8c1d8c.zip
op-kernel-dev-31de198b4d2732028f4c5bff04b0103b1d8c1d8c.tar.gz
gianfar: Add macros for stepping through BDs
This code is based strongly on code from Dai Haruki <Dai.Haruki@freescale.com>. The gianfar Buffer Descriptors are arranged in a circular array, the end of which is denoted by setting the "WRAP" bit in the descriptor. However, the software knows the end of the ring because it knows how many descriptors are there. Rather than check each descriptor for whether the WRAP bit is set, use pointer math to determine where the next BD is. This is also useful for when we want to look at BDs other than the very next one (for Scatter-Gather). Signed-off-by: Andy Fleming <afleming@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/gianfar.c27
-rw-r--r--drivers/net/gianfar.h6
2 files changed, 15 insertions, 18 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 40756dc..e7e8201 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1215,7 +1215,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct txfcb *fcb = NULL;
- struct txbd8 *txbdp;
+ struct txbd8 *txbdp, *base;
u16 status;
unsigned long flags;
@@ -1227,6 +1227,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Point at the first free tx descriptor */
txbdp = priv->cur_tx;
+ base = priv->tx_bd_base;
/* Clear all but the WRAP status flags */
status = txbdp->status & TXBD_WRAP;
@@ -1279,12 +1280,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
eieio();
txbdp->status = status;
- /* If this was the last BD in the ring, the next one */
- /* is at the beginning of the ring */
- if (txbdp->status & TXBD_WRAP)
- txbdp = priv->tx_bd_base;
- else
- txbdp++;
+ txbdp = next_bd(txbdp, base, priv->tx_ring_size);
/* If the next BD still needs to be cleaned up, then the bds
are full. We need to tell the kernel to stop sending us stuff. */
@@ -1470,11 +1466,12 @@ static void gfar_timeout(struct net_device *dev)
/* Interrupt Handler for Transmit complete */
static int gfar_clean_tx_ring(struct net_device *dev)
{
- struct txbd8 *bdp;
+ struct txbd8 *bdp, *base;
struct gfar_private *priv = netdev_priv(dev);
int howmany = 0;
bdp = priv->dirty_tx;
+ base = priv->tx_bd_base;
while ((bdp->status & TXBD_READY) == 0) {
/* If dirty_tx and cur_tx are the same, then either the */
/* ring is empty or full now (it could only be full in the beginning, */
@@ -1504,11 +1501,7 @@ static int gfar_clean_tx_ring(struct net_device *dev)
/* Clean BD length for empty detection */
bdp->length = 0;
- /* update bdp to point at next bd in the ring (wrapping if necessary) */
- if (bdp->status & TXBD_WRAP)
- bdp = priv->tx_bd_base;
- else
- bdp++;
+ bdp = next_bd(bdp, base, priv->tx_ring_size);
/* Move dirty_tx to be the next bd */
priv->dirty_tx = bdp;
@@ -1712,7 +1705,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
*/
int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
{
- struct rxbd8 *bdp;
+ struct rxbd8 *bdp, *base;
struct sk_buff *skb;
int pkt_len;
int amount_pull;
@@ -1721,6 +1714,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
/* Get the first full descriptor */
bdp = priv->cur_rx;
+ base = priv->rx_bd_base;
amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) +
priv->padding;
@@ -1776,10 +1770,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
gfar_new_rxbdp(dev, bdp, newskb);
/* Update to the next pointer */
- if (bdp->status & RXBD_WRAP)
- bdp = priv->rx_bd_base;
- else
- bdp++;
+ bdp = next_bd(bdp, base, priv->rx_ring_size);
/* update to point at the next skb */
priv->skb_currx =
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 1bdb50c..1ebf7ac 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -196,6 +196,12 @@ extern const char gfar_driver_version[];
#define DEFAULT_TXIC mk_ic_value(DEFAULT_TXCOUNT, DEFAULT_TXTIME)
#define DEFAULT_RXIC mk_ic_value(DEFAULT_RXCOUNT, DEFAULT_RXTIME)
+#define skip_bd(bdp, stride, base, ring_size) ({ \
+ typeof(bdp) new_bd = (bdp) + (stride); \
+ (new_bd >= (base) + (ring_size)) ? (new_bd - (ring_size)) : new_bd; })
+
+#define next_bd(bdp, base, ring_size) skip_bd(bdp, 1, base, ring_size)
+
#define RCTRL_PAL_MASK 0x001f0000
#define RCTRL_VLEX 0x00002000
#define RCTRL_FILREN 0x00001000
OpenPOWER on IntegriCloud