diff options
Diffstat (limited to 'drivers/net/gianfar.c')
-rw-r--r-- | drivers/net/gianfar.c | 87 |
1 files changed, 41 insertions, 46 deletions
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 6dc9361495bb..9057a1df8e94 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 |
132 | int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); | 132 | int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); |
133 | static int gfar_clean_tx_ring(struct net_device *dev); | 133 | static int gfar_clean_tx_ring(struct net_device *dev); |
134 | static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); | 134 | static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, |
135 | int amount_pull); | ||
135 | static void gfar_vlan_rx_register(struct net_device *netdev, | 136 | static void gfar_vlan_rx_register(struct net_device *netdev, |
136 | struct vlan_group *grp); | 137 | struct vlan_group *grp); |
137 | void gfar_halt(struct net_device *dev); | 138 | void 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 | ||
1671 | static 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. */ |
1683 | static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, | 1675 | static 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; |