|
@@ -821,6 +821,7 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
|
|
|
struct bcm_sysport_cb *cb;
|
|
|
struct netdev_queue *txq;
|
|
|
struct dma_desc *desc;
|
|
|
+ unsigned int skb_len;
|
|
|
dma_addr_t mapping;
|
|
|
u32 len_status;
|
|
|
u16 queue;
|
|
@@ -848,10 +849,25 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- mapping = dma_map_single(kdev, skb->data, skb->len, DMA_TO_DEVICE);
|
|
|
+ /* The Ethernet switch we are interfaced with needs packets to be at
|
|
|
+ * least 64 bytes (including FCS) otherwise they will be discarded when
|
|
|
+ * they enter the switch port logic. When Broadcom tags are enabled, we
|
|
|
+ * need to make sure that packets are at least 68 bytes
|
|
|
+ * (including FCS and tag) because the length verification is done after
|
|
|
+ * the Broadcom tag is stripped off the ingress packet.
|
|
|
+ */
|
|
|
+ if (skb_padto(skb, ETH_ZLEN + ENET_BRCM_TAG_LEN)) {
|
|
|
+ ret = NETDEV_TX_OK;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ skb_len = skb->len < ETH_ZLEN + ENET_BRCM_TAG_LEN ?
|
|
|
+ ETH_ZLEN + ENET_BRCM_TAG_LEN : skb->len;
|
|
|
+
|
|
|
+ mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE);
|
|
|
if (dma_mapping_error(kdev, mapping)) {
|
|
|
netif_err(priv, tx_err, dev, "DMA map failed at %p (len=%d)\n",
|
|
|
- skb->data, skb->len);
|
|
|
+ skb->data, skb_len);
|
|
|
ret = NETDEV_TX_OK;
|
|
|
goto out;
|
|
|
}
|
|
@@ -860,14 +876,14 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
|
|
|
cb = &ring->cbs[ring->curr_desc];
|
|
|
cb->skb = skb;
|
|
|
dma_unmap_addr_set(cb, dma_addr, mapping);
|
|
|
- dma_unmap_len_set(cb, dma_len, skb->len);
|
|
|
+ dma_unmap_len_set(cb, dma_len, skb_len);
|
|
|
|
|
|
/* Fetch a descriptor entry from our pool */
|
|
|
desc = ring->desc_cpu;
|
|
|
|
|
|
desc->addr_lo = lower_32_bits(mapping);
|
|
|
len_status = upper_32_bits(mapping) & DESC_ADDR_HI_MASK;
|
|
|
- len_status |= (skb->len << DESC_LEN_SHIFT);
|
|
|
+ len_status |= (skb_len << DESC_LEN_SHIFT);
|
|
|
len_status |= (DESC_SOP | DESC_EOP | TX_STATUS_APP_CRC) <<
|
|
|
DESC_STATUS_SHIFT;
|
|
|
if (skb->ip_summed == CHECKSUM_PARTIAL)
|