|
@@ -10,6 +10,7 @@
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
#include <linux/clk.h>
|
|
#include <linux/clk.h>
|
|
|
|
+#include <linux/crc32.h>
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kernel.h>
|
|
@@ -1565,6 +1566,9 @@ static unsigned int macb_tx_map(struct macb *bp,
|
|
if (i == queue->tx_head) {
|
|
if (i == queue->tx_head) {
|
|
ctrl |= MACB_BF(TX_LSO, lso_ctrl);
|
|
ctrl |= MACB_BF(TX_LSO, lso_ctrl);
|
|
ctrl |= MACB_BF(TX_TCP_SEQ_SRC, seq_ctrl);
|
|
ctrl |= MACB_BF(TX_TCP_SEQ_SRC, seq_ctrl);
|
|
|
|
+ if ((bp->dev->features & NETIF_F_HW_CSUM) &&
|
|
|
|
+ skb->ip_summed != CHECKSUM_PARTIAL && !lso_ctrl)
|
|
|
|
+ ctrl |= MACB_BIT(TX_NOCRC);
|
|
} else
|
|
} else
|
|
/* Only set MSS/MFS on payload descriptors
|
|
/* Only set MSS/MFS on payload descriptors
|
|
* (second or later descriptor)
|
|
* (second or later descriptor)
|
|
@@ -1651,6 +1655,67 @@ static inline int macb_clear_csum(struct sk_buff *skb)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int macb_pad_and_fcs(struct sk_buff **skb, struct net_device *ndev)
|
|
|
|
+{
|
|
|
|
+ bool cloned = skb_cloned(*skb) || skb_header_cloned(*skb);
|
|
|
|
+ int padlen = ETH_ZLEN - (*skb)->len;
|
|
|
|
+ int headroom = skb_headroom(*skb);
|
|
|
|
+ int tailroom = skb_tailroom(*skb);
|
|
|
|
+ struct sk_buff *nskb;
|
|
|
|
+ u32 fcs;
|
|
|
|
+
|
|
|
|
+ if (!(ndev->features & NETIF_F_HW_CSUM) ||
|
|
|
|
+ !((*skb)->ip_summed != CHECKSUM_PARTIAL) ||
|
|
|
|
+ skb_shinfo(*skb)->gso_size) /* Not available for GSO */
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ if (padlen <= 0) {
|
|
|
|
+ /* FCS could be appeded to tailroom. */
|
|
|
|
+ if (tailroom >= ETH_FCS_LEN)
|
|
|
|
+ goto add_fcs;
|
|
|
|
+ /* FCS could be appeded by moving data to headroom. */
|
|
|
|
+ else if (!cloned && headroom + tailroom >= ETH_FCS_LEN)
|
|
|
|
+ padlen = 0;
|
|
|
|
+ /* No room for FCS, need to reallocate skb. */
|
|
|
|
+ else
|
|
|
|
+ padlen = ETH_FCS_LEN - tailroom;
|
|
|
|
+ } else {
|
|
|
|
+ /* Add room for FCS. */
|
|
|
|
+ padlen += ETH_FCS_LEN;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!cloned && headroom + tailroom >= padlen) {
|
|
|
|
+ (*skb)->data = memmove((*skb)->head, (*skb)->data, (*skb)->len);
|
|
|
|
+ skb_set_tail_pointer(*skb, (*skb)->len);
|
|
|
|
+ } else {
|
|
|
|
+ nskb = skb_copy_expand(*skb, 0, padlen, GFP_ATOMIC);
|
|
|
|
+ if (!nskb)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ dev_kfree_skb_any(*skb);
|
|
|
|
+ *skb = nskb;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (padlen) {
|
|
|
|
+ if (padlen >= ETH_FCS_LEN)
|
|
|
|
+ skb_put_zero(*skb, padlen - ETH_FCS_LEN);
|
|
|
|
+ else
|
|
|
|
+ skb_trim(*skb, ETH_FCS_LEN - padlen);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+add_fcs:
|
|
|
|
+ /* set FCS to packet */
|
|
|
|
+ fcs = crc32_le(~0, (*skb)->data, (*skb)->len);
|
|
|
|
+ fcs = ~fcs;
|
|
|
|
+
|
|
|
|
+ skb_put_u8(*skb, fcs & 0xff);
|
|
|
|
+ skb_put_u8(*skb, (fcs >> 8) & 0xff);
|
|
|
|
+ skb_put_u8(*skb, (fcs >> 16) & 0xff);
|
|
|
|
+ skb_put_u8(*skb, (fcs >> 24) & 0xff);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
{
|
|
{
|
|
u16 queue_index = skb_get_queue_mapping(skb);
|
|
u16 queue_index = skb_get_queue_mapping(skb);
|
|
@@ -1667,6 +1732,11 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (macb_pad_and_fcs(&skb, dev)) {
|
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
is_lso = (skb_shinfo(skb)->gso_size != 0);
|
|
is_lso = (skb_shinfo(skb)->gso_size != 0);
|
|
|
|
|
|
if (is_lso) {
|
|
if (is_lso) {
|