aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/gianfar.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/gianfar.c')
-rw-r--r--drivers/net/gianfar.c87
1 files changed, 41 insertions, 46 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 6dc9361495b..9057a1df8e9 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -131,7 +131,8 @@ static void gfar_netpoll(struct net_device *dev);
131#endif 131#endif
132int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); 132int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
133static int gfar_clean_tx_ring(struct net_device *dev); 133static int gfar_clean_tx_ring(struct net_device *dev);
134static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); 134static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
135 int amount_pull);
135static void gfar_vlan_rx_register(struct net_device *netdev, 136static void gfar_vlan_rx_register(struct net_device *netdev,
136 struct vlan_group *grp); 137 struct vlan_group *grp);
137void gfar_halt(struct net_device *dev); 138void gfar_halt(struct net_device *dev);
@@ -210,6 +211,7 @@ static int gfar_of_init(struct net_device *dev)
210 FSL_GIANFAR_DEV_HAS_COALESCE | 211 FSL_GIANFAR_DEV_HAS_COALESCE |
211 FSL_GIANFAR_DEV_HAS_RMON | 212 FSL_GIANFAR_DEV_HAS_RMON |
212 FSL_GIANFAR_DEV_HAS_MULTI_INTR | 213 FSL_GIANFAR_DEV_HAS_MULTI_INTR |
214 FSL_GIANFAR_DEV_HAS_PADDING |
213 FSL_GIANFAR_DEV_HAS_CSUM | 215 FSL_GIANFAR_DEV_HAS_CSUM |
214 FSL_GIANFAR_DEV_HAS_VLAN | 216 FSL_GIANFAR_DEV_HAS_VLAN |
215 FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | 217 FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
@@ -1668,59 +1670,38 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
1668} 1670}
1669 1671
1670 1672
1671static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
1672{
1673 struct rxfcb *fcb = (struct rxfcb *)skb->data;
1674
1675 /* Remove the FCB from the skb */
1676 skb_pull(skb, GMAC_FCB_LEN);
1677
1678 return fcb;
1679}
1680
1681/* gfar_process_frame() -- handle one incoming packet if skb 1673/* gfar_process_frame() -- handle one incoming packet if skb
1682 * isn't NULL. */ 1674 * isn't NULL. */
1683static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, 1675static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
1684 int length) 1676 int amount_pull)
1685{ 1677{
1686 struct gfar_private *priv = netdev_priv(dev); 1678 struct gfar_private *priv = netdev_priv(dev);
1687 struct rxfcb *fcb = NULL; 1679 struct rxfcb *fcb = NULL;
1688 1680
1689 if (NULL == skb) { 1681 int ret;
1690 if (netif_msg_rx_err(priv))
1691 printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
1692 dev->stats.rx_dropped++;
1693 priv->extra_stats.rx_skbmissing++;
1694 } else {
1695 int ret;
1696 1682
1697 /* Prep the skb for the packet */ 1683 /* fcb is at the beginning if exists */
1698 skb_put(skb, length); 1684 fcb = (struct rxfcb *)skb->data;
1699 1685
1700 /* Grab the FCB if there is one */ 1686 /* Remove the FCB from the skb */
1701 if (gfar_uses_fcb(priv)) 1687 /* Remove the padded bytes, if there are any */
1702 fcb = gfar_get_fcb(skb); 1688 if (amount_pull)
1703 1689 skb_pull(skb, amount_pull);
1704 /* Remove the padded bytes, if there are any */
1705 if (priv->padding)
1706 skb_pull(skb, priv->padding);
1707 1690
1708 if (priv->rx_csum_enable) 1691 if (priv->rx_csum_enable)
1709 gfar_rx_checksum(skb, fcb); 1692 gfar_rx_checksum(skb, fcb);
1710 1693
1711 /* Tell the skb what kind of packet this is */ 1694 /* Tell the skb what kind of packet this is */
1712 skb->protocol = eth_type_trans(skb, dev); 1695 skb->protocol = eth_type_trans(skb, dev);
1713 1696
1714 /* Send the packet up the stack */ 1697 /* Send the packet up the stack */
1715 if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) { 1698 if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN)))
1716 ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, 1699 ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, fcb->vlctl);
1717 fcb->vlctl); 1700 else
1718 } else 1701 ret = netif_receive_skb(skb);
1719 ret = netif_receive_skb(skb);
1720 1702
1721 if (NET_RX_DROP == ret) 1703 if (NET_RX_DROP == ret)
1722 priv->extra_stats.kernel_dropped++; 1704 priv->extra_stats.kernel_dropped++;
1723 }
1724 1705
1725 return 0; 1706 return 0;
1726} 1707}
@@ -1733,13 +1714,17 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
1733{ 1714{
1734 struct rxbd8 *bdp; 1715 struct rxbd8 *bdp;
1735 struct sk_buff *skb; 1716 struct sk_buff *skb;
1736 u16 pkt_len; 1717 int pkt_len;
1718 int amount_pull;
1737 int howmany = 0; 1719 int howmany = 0;
1738 struct gfar_private *priv = netdev_priv(dev); 1720 struct gfar_private *priv = netdev_priv(dev);
1739 1721
1740 /* Get the first full descriptor */ 1722 /* Get the first full descriptor */
1741 bdp = priv->cur_rx; 1723 bdp = priv->cur_rx;
1742 1724
1725 amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) +
1726 priv->padding;
1727
1743 while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { 1728 while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) {
1744 struct sk_buff *newskb; 1729 struct sk_buff *newskb;
1745 rmb(); 1730 rmb();
@@ -1767,12 +1752,22 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
1767 dev->stats.rx_packets++; 1752 dev->stats.rx_packets++;
1768 howmany++; 1753 howmany++;
1769 1754
1770 /* Remove the FCS from the packet length */ 1755 if (likely(skb)) {
1771 pkt_len = bdp->length - 4; 1756 pkt_len = bdp->length - ETH_FCS_LEN;
1757 /* Remove the FCS from the packet length */
1758 skb_put(skb, pkt_len);
1759 dev->stats.rx_bytes += pkt_len;
1760
1761 gfar_process_frame(dev, skb, amount_pull);
1772 1762
1773 gfar_process_frame(dev, skb, pkt_len); 1763 } else {
1764 if (netif_msg_rx_err(priv))
1765 printk(KERN_WARNING
1766 "%s: Missing skb!\n", dev->name);
1767 dev->stats.rx_dropped++;
1768 priv->extra_stats.rx_skbmissing++;
1769 }
1774 1770
1775 dev->stats.rx_bytes += pkt_len;
1776 } 1771 }
1777 1772
1778 priv->rx_skbuff[priv->skb_currx] = newskb; 1773 priv->rx_skbuff[priv->skb_currx] = newskb;