gianfar: Enable padding and Optimize the frame prepended bytes handling
The eTSEC can prepend up to 32 bytes to a received frame, usually for the purpose of aligning the IP address to a word boundary, so this turns it on. While we're in there, make the handling of the pre-frame bytes (padding and Frame Control Block) cleaner. Signed-off-by: Dai Haruki <dai.haruki@freescale.com> Signed-off-by: Andy Fleming <afleming@freescale.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
77ecaf2d5a
commit
2c2db48acb
1 changed files with 41 additions and 46 deletions
|
@ -131,7 +131,8 @@ static void gfar_netpoll(struct net_device *dev);
|
||||||
#endif
|
#endif
|
||||||
int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
|
int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
|
||||||
static int gfar_clean_tx_ring(struct net_device *dev);
|
static int gfar_clean_tx_ring(struct net_device *dev);
|
||||||
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
|
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
|
||||||
|
int amount_pull);
|
||||||
static void gfar_vlan_rx_register(struct net_device *netdev,
|
static void gfar_vlan_rx_register(struct net_device *netdev,
|
||||||
struct vlan_group *grp);
|
struct vlan_group *grp);
|
||||||
void gfar_halt(struct net_device *dev);
|
void gfar_halt(struct net_device *dev);
|
||||||
|
@ -210,6 +211,7 @@ static int gfar_of_init(struct net_device *dev)
|
||||||
FSL_GIANFAR_DEV_HAS_COALESCE |
|
FSL_GIANFAR_DEV_HAS_COALESCE |
|
||||||
FSL_GIANFAR_DEV_HAS_RMON |
|
FSL_GIANFAR_DEV_HAS_RMON |
|
||||||
FSL_GIANFAR_DEV_HAS_MULTI_INTR |
|
FSL_GIANFAR_DEV_HAS_MULTI_INTR |
|
||||||
|
FSL_GIANFAR_DEV_HAS_PADDING |
|
||||||
FSL_GIANFAR_DEV_HAS_CSUM |
|
FSL_GIANFAR_DEV_HAS_CSUM |
|
||||||
FSL_GIANFAR_DEV_HAS_VLAN |
|
FSL_GIANFAR_DEV_HAS_VLAN |
|
||||||
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
|
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
|
||||||
|
@ -1668,59 +1670,38 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct rxfcb *fcb = (struct rxfcb *)skb->data;
|
|
||||||
|
|
||||||
/* Remove the FCB from the skb */
|
|
||||||
skb_pull(skb, GMAC_FCB_LEN);
|
|
||||||
|
|
||||||
return fcb;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* gfar_process_frame() -- handle one incoming packet if skb
|
/* gfar_process_frame() -- handle one incoming packet if skb
|
||||||
* isn't NULL. */
|
* isn't NULL. */
|
||||||
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
|
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
|
||||||
int length)
|
int amount_pull)
|
||||||
{
|
{
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
struct rxfcb *fcb = NULL;
|
struct rxfcb *fcb = NULL;
|
||||||
|
|
||||||
if (NULL == skb) {
|
int ret;
|
||||||
if (netif_msg_rx_err(priv))
|
|
||||||
printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
|
|
||||||
dev->stats.rx_dropped++;
|
|
||||||
priv->extra_stats.rx_skbmissing++;
|
|
||||||
} else {
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Prep the skb for the packet */
|
/* fcb is at the beginning if exists */
|
||||||
skb_put(skb, length);
|
fcb = (struct rxfcb *)skb->data;
|
||||||
|
|
||||||
/* Grab the FCB if there is one */
|
/* Remove the FCB from the skb */
|
||||||
if (gfar_uses_fcb(priv))
|
/* Remove the padded bytes, if there are any */
|
||||||
fcb = gfar_get_fcb(skb);
|
if (amount_pull)
|
||||||
|
skb_pull(skb, amount_pull);
|
||||||
|
|
||||||
/* Remove the padded bytes, if there are any */
|
if (priv->rx_csum_enable)
|
||||||
if (priv->padding)
|
gfar_rx_checksum(skb, fcb);
|
||||||
skb_pull(skb, priv->padding);
|
|
||||||
|
|
||||||
if (priv->rx_csum_enable)
|
/* Tell the skb what kind of packet this is */
|
||||||
gfar_rx_checksum(skb, fcb);
|
skb->protocol = eth_type_trans(skb, dev);
|
||||||
|
|
||||||
/* Tell the skb what kind of packet this is */
|
/* Send the packet up the stack */
|
||||||
skb->protocol = eth_type_trans(skb, dev);
|
if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN)))
|
||||||
|
ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, fcb->vlctl);
|
||||||
|
else
|
||||||
|
ret = netif_receive_skb(skb);
|
||||||
|
|
||||||
/* Send the packet up the stack */
|
if (NET_RX_DROP == ret)
|
||||||
if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) {
|
priv->extra_stats.kernel_dropped++;
|
||||||
ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp,
|
|
||||||
fcb->vlctl);
|
|
||||||
} else
|
|
||||||
ret = netif_receive_skb(skb);
|
|
||||||
|
|
||||||
if (NET_RX_DROP == ret)
|
|
||||||
priv->extra_stats.kernel_dropped++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1733,13 +1714,17 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
|
||||||
{
|
{
|
||||||
struct rxbd8 *bdp;
|
struct rxbd8 *bdp;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
u16 pkt_len;
|
int pkt_len;
|
||||||
|
int amount_pull;
|
||||||
int howmany = 0;
|
int howmany = 0;
|
||||||
struct gfar_private *priv = netdev_priv(dev);
|
struct gfar_private *priv = netdev_priv(dev);
|
||||||
|
|
||||||
/* Get the first full descriptor */
|
/* Get the first full descriptor */
|
||||||
bdp = priv->cur_rx;
|
bdp = priv->cur_rx;
|
||||||
|
|
||||||
|
amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) +
|
||||||
|
priv->padding;
|
||||||
|
|
||||||
while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
|
while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
|
||||||
struct sk_buff *newskb;
|
struct sk_buff *newskb;
|
||||||
rmb();
|
rmb();
|
||||||
|
@ -1767,12 +1752,22 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
|
||||||
dev->stats.rx_packets++;
|
dev->stats.rx_packets++;
|
||||||
howmany++;
|
howmany++;
|
||||||
|
|
||||||
/* Remove the FCS from the packet length */
|
if (likely(skb)) {
|
||||||
pkt_len = bdp->length - 4;
|
pkt_len = bdp->length - ETH_FCS_LEN;
|
||||||
|
/* Remove the FCS from the packet length */
|
||||||
|
skb_put(skb, pkt_len);
|
||||||
|
dev->stats.rx_bytes += pkt_len;
|
||||||
|
|
||||||
gfar_process_frame(dev, skb, pkt_len);
|
gfar_process_frame(dev, skb, amount_pull);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (netif_msg_rx_err(priv))
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"%s: Missing skb!\n", dev->name);
|
||||||
|
dev->stats.rx_dropped++;
|
||||||
|
priv->extra_stats.rx_skbmissing++;
|
||||||
|
}
|
||||||
|
|
||||||
dev->stats.rx_bytes += pkt_len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->rx_skbuff[priv->skb_currx] = newskb;
|
priv->rx_skbuff[priv->skb_currx] = newskb;
|
||||||
|
|
Loading…
Reference in a new issue