|
@@ -601,14 +601,24 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
|
|
|
return NETDEV_TX_OK;
|
|
|
}
|
|
|
|
|
|
-static void xgene_enet_skip_csum(struct sk_buff *skb)
|
|
|
+static void xgene_enet_rx_csum(struct sk_buff *skb)
|
|
|
{
|
|
|
+ struct net_device *ndev = skb->dev;
|
|
|
struct iphdr *iph = ip_hdr(skb);
|
|
|
|
|
|
- if (!ip_is_fragment(iph) ||
|
|
|
- (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) {
|
|
|
- skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
- }
|
|
|
+ if (!(ndev->features & NETIF_F_RXCSUM))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (skb->protocol != htons(ETH_P_IP))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (ip_is_fragment(iph))
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)
|
|
|
+ return;
|
|
|
+
|
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
}
|
|
|
|
|
|
static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool,
|
|
@@ -648,12 +658,24 @@ static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool,
|
|
|
buf_pool->head = head;
|
|
|
}
|
|
|
|
|
|
+/* Errata 10GE_8 and ENET_11 - allow packet with length <=64B */
|
|
|
+static bool xgene_enet_errata_10GE_8(struct sk_buff *skb, u32 len, u8 status)
|
|
|
+{
|
|
|
+ if (status == INGRESS_PKT_LEN && len == ETHER_MIN_PACKET) {
|
|
|
+ if (ntohs(eth_hdr(skb)->h_proto) < 46)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
|
|
|
struct xgene_enet_raw_desc *raw_desc,
|
|
|
struct xgene_enet_raw_desc *exp_desc)
|
|
|
{
|
|
|
struct xgene_enet_desc_ring *buf_pool, *page_pool;
|
|
|
u32 datalen, frag_size, skb_index;
|
|
|
+ struct xgene_enet_pdata *pdata;
|
|
|
struct net_device *ndev;
|
|
|
dma_addr_t dma_addr;
|
|
|
struct sk_buff *skb;
|
|
@@ -666,6 +688,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
|
|
|
bool nv;
|
|
|
|
|
|
ndev = rx_ring->ndev;
|
|
|
+ pdata = netdev_priv(ndev);
|
|
|
dev = ndev_to_dev(rx_ring->ndev);
|
|
|
buf_pool = rx_ring->buf_pool;
|
|
|
page_pool = rx_ring->page_pool;
|
|
@@ -676,30 +699,29 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
|
|
|
skb = buf_pool->rx_skb[skb_index];
|
|
|
buf_pool->rx_skb[skb_index] = NULL;
|
|
|
|
|
|
+ datalen = xgene_enet_get_data_len(le64_to_cpu(raw_desc->m1));
|
|
|
+ skb_put(skb, datalen);
|
|
|
+ prefetch(skb->data - NET_IP_ALIGN);
|
|
|
+ skb->protocol = eth_type_trans(skb, ndev);
|
|
|
+
|
|
|
/* checking for error */
|
|
|
- status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) ||
|
|
|
+ status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) |
|
|
|
GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
|
|
|
- if (unlikely(status > 2)) {
|
|
|
- dev_kfree_skb_any(skb);
|
|
|
- xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc);
|
|
|
- xgene_enet_parse_error(rx_ring, netdev_priv(rx_ring->ndev),
|
|
|
- status);
|
|
|
- ret = -EIO;
|
|
|
- goto out;
|
|
|
+ if (unlikely(status)) {
|
|
|
+ if (!xgene_enet_errata_10GE_8(skb, datalen, status)) {
|
|
|
+ dev_kfree_skb_any(skb);
|
|
|
+ xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc);
|
|
|
+ xgene_enet_parse_error(rx_ring, pdata, status);
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- /* strip off CRC as HW isn't doing this */
|
|
|
- datalen = xgene_enet_get_data_len(le64_to_cpu(raw_desc->m1));
|
|
|
-
|
|
|
nv = GET_VAL(NV, le64_to_cpu(raw_desc->m0));
|
|
|
- if (!nv)
|
|
|
+ if (!nv) {
|
|
|
+ /* strip off CRC as HW isn't doing this */
|
|
|
datalen -= 4;
|
|
|
-
|
|
|
- skb_put(skb, datalen);
|
|
|
- prefetch(skb->data - NET_IP_ALIGN);
|
|
|
-
|
|
|
- if (!nv)
|
|
|
goto skip_jumbo;
|
|
|
+ }
|
|
|
|
|
|
slots = page_pool->slots - 1;
|
|
|
head = page_pool->head;
|
|
@@ -728,11 +750,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
|
|
|
|
|
|
skip_jumbo:
|
|
|
skb_checksum_none_assert(skb);
|
|
|
- skb->protocol = eth_type_trans(skb, ndev);
|
|
|
- if (likely((ndev->features & NETIF_F_IP_CSUM) &&
|
|
|
- skb->protocol == htons(ETH_P_IP))) {
|
|
|
- xgene_enet_skip_csum(skb);
|
|
|
- }
|
|
|
+ xgene_enet_rx_csum(skb);
|
|
|
|
|
|
rx_ring->rx_packets++;
|
|
|
rx_ring->rx_bytes += datalen;
|
|
@@ -2039,7 +2057,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
|
|
|
xgene_enet_setup_ops(pdata);
|
|
|
|
|
|
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
|
|
|
- ndev->features |= NETIF_F_TSO;
|
|
|
+ ndev->features |= NETIF_F_TSO | NETIF_F_RXCSUM;
|
|
|
spin_lock_init(&pdata->mss_lock);
|
|
|
}
|
|
|
ndev->hw_features = ndev->features;
|