aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/net/ethernet/broadcom/bcmsysport.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/broadcom/bcmsysport.c')
-rw-r--r--drivers/net/ethernet/broadcom/bcmsysport.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c
index b25356e21a1e..dfed9ade6950 100644
--- a/drivers/net/ethernet/broadcom/bcmsysport.c
+++ b/drivers/net/ethernet/broadcom/bcmsysport.c
@@ -160,13 +160,26 @@ static void bcm_sysport_set_tx_csum(struct net_device *dev,
/* Hardware transmit checksum requires us to enable the Transmit status
* block prepended to the packet contents
*/
- priv->tsb_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM));
+ priv->tsb_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_HW_VLAN_CTAG_TX));
reg = tdma_readl(priv, TDMA_CONTROL);
if (priv->tsb_en)
reg |= tdma_control_bit(priv, TSB_EN);
else
reg &= ~tdma_control_bit(priv, TSB_EN);
+ /* Indicating that software inserts Broadcom tags is needed for the TX
+ * checksum to be computed correctly when using VLAN HW acceleration,
+ * else it has no effect, so it can always be turned on.
+ */
+ if (netdev_uses_dsa(dev))
+ reg |= tdma_control_bit(priv, SW_BRCM_TAG);
+ else
+ reg &= ~tdma_control_bit(priv, SW_BRCM_TAG);
tdma_writel(priv, reg, TDMA_CONTROL);
+
+ /* Default TPID is ETH_P_8021AD, change to ETH_P_8021Q */
+ if (wanted & NETIF_F_HW_VLAN_CTAG_TX)
+ tdma_writel(priv, ETH_P_8021Q, TDMA_TPID);
}
static int bcm_sysport_set_features(struct net_device *dev,
@@ -1236,6 +1249,11 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb,
/* Zero-out TSB by default */
memset(tsb, 0, sizeof(*tsb));
+ if (skb_vlan_tag_present(skb)) {
+ tsb->pcp_dei_vid = skb_vlan_tag_get_prio(skb) & PCP_DEI_MASK;
+ tsb->pcp_dei_vid |= (u32)skb_vlan_tag_get_id(skb) << VID_SHIFT;
+ }
+
if (skb->ip_summed == CHECKSUM_PARTIAL) {
ip_ver = skb->protocol;
switch (ip_ver) {
@@ -1251,6 +1269,9 @@ static struct sk_buff *bcm_sysport_insert_tsb(struct sk_buff *skb,
/* Get the checksum offset and the L4 (transport) offset */
csum_start = skb_checksum_start_offset(skb) - sizeof(*tsb);
+ /* Account for the HW inserted VLAN tag */
+ if (skb_vlan_tag_present(skb))
+ csum_start += VLAN_HLEN;
csum_info = (csum_start + skb->csum_offset) & L4_CSUM_PTR_MASK;
csum_info |= (csum_start << L4_PTR_SHIFT);
@@ -1330,6 +1351,8 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb,
DESC_STATUS_SHIFT;
if (skb->ip_summed == CHECKSUM_PARTIAL)
len_status |= (DESC_L4_CSUM << DESC_STATUS_SHIFT);
+ if (skb_vlan_tag_present(skb))
+ len_status |= (TX_STATUS_VLAN_VID_TSB << DESC_STATUS_SHIFT);
ring->curr_desc++;
if (ring->curr_desc == ring->size)
@@ -1503,7 +1526,13 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
reg |= RING_IGNORE_STATUS;
}
tdma_writel(priv, reg, TDMA_DESC_RING_MAPPING(index));
- tdma_writel(priv, 0, TDMA_DESC_RING_PCP_DEI_VID(index));
+ reg = 0;
+ /* Adjust the packet size calculations if SYSTEMPORT is responsible
+ * for HW insertion of VLAN tags
+ */
+ if (priv->netdev->features & NETIF_F_HW_VLAN_CTAG_TX)
+ reg = VLAN_HLEN << RING_PKT_SIZE_ADJ_SHIFT;
+ tdma_writel(priv, reg, TDMA_DESC_RING_PCP_DEI_VID(index));
/* Enable ACB algorithm 2 */
reg = tdma_readl(priv, TDMA_CONTROL);
@@ -2523,7 +2552,8 @@ static int bcm_sysport_probe(struct platform_device *pdev)
netif_napi_add(dev, &priv->napi, bcm_sysport_poll, 64);
dev->features |= NETIF_F_RXCSUM | NETIF_F_HIGHDMA |
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_HW_VLAN_CTAG_TX;
dev->hw_features |= dev->features;
dev->vlan_features |= dev->features;