Skip to content

Commit 750011e

Browse files
ganyifangdavem330
authored andcommitted
net: stmmac: Add support for HW-accelerated VLAN stripping
Current implementation supports driver level VLAN tag stripping only. The features is always on if CONFIG_VLAN_8021Q is enabled in kernel config and is not user configurable. This patch add support to MAC level VLAN tag stripping and can be configured through ethtool. If the rx-vlan-offload is off, the VLAN tag will be stripped by driver. If the rx-vlan-offload is on, the VLAN tag will be stripped by MAC. Command: ethtool -K <interface> rx-vlan-offload off | on Signed-off-by: Lai Peter Jun Ann <[email protected]> Signed-off-by: Gan, Yi Fang <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 36b20fc commit 750011e

File tree

5 files changed

+90
-2
lines changed

5 files changed

+90
-2
lines changed

drivers/net/ethernet/stmicro/stmmac/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ struct mac_device_info {
580580
u32 vlan_filter[32];
581581
bool vlan_fail_q_en;
582582
u8 vlan_fail_q;
583+
bool hw_vlan_en;
583584
};
584585

585586
struct stmmac_rx_routing {

drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,6 +1134,35 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
11341134
return 0;
11351135
}
11361136

1137+
static void dwmac4_rx_hw_vlan(struct mac_device_info *hw,
1138+
struct dma_desc *rx_desc, struct sk_buff *skb)
1139+
{
1140+
if (hw->desc->get_rx_vlan_valid(rx_desc)) {
1141+
u16 vid = hw->desc->get_rx_vlan_tci(rx_desc);
1142+
1143+
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid);
1144+
}
1145+
}
1146+
1147+
static void dwmac4_set_hw_vlan_mode(struct mac_device_info *hw)
1148+
{
1149+
void __iomem *ioaddr = hw->pcsr;
1150+
u32 value = readl(ioaddr + GMAC_VLAN_TAG);
1151+
1152+
value &= ~GMAC_VLAN_TAG_CTRL_EVLS_MASK;
1153+
1154+
if (hw->hw_vlan_en)
1155+
/* Always strip VLAN on Receive */
1156+
value |= GMAC_VLAN_TAG_STRIP_ALL;
1157+
else
1158+
/* Do not strip VLAN on Receive */
1159+
value |= GMAC_VLAN_TAG_STRIP_NONE;
1160+
1161+
/* Enable outer VLAN Tag in Rx DMA descriptor */
1162+
value |= GMAC_VLAN_TAG_CTRL_EVLRXS;
1163+
writel(value, ioaddr + GMAC_VLAN_TAG);
1164+
}
1165+
11371166
const struct stmmac_ops dwmac4_ops = {
11381167
.core_init = dwmac4_core_init,
11391168
.phylink_get_caps = dwmac4_phylink_get_caps,
@@ -1175,6 +1204,8 @@ const struct stmmac_ops dwmac4_ops = {
11751204
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
11761205
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
11771206
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
1207+
.rx_hw_vlan = dwmac4_rx_hw_vlan,
1208+
.set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
11781209
};
11791210

11801211
const struct stmmac_ops dwmac410_ops = {
@@ -1224,6 +1255,8 @@ const struct stmmac_ops dwmac410_ops = {
12241255
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
12251256
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
12261257
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
1258+
.rx_hw_vlan = dwmac4_rx_hw_vlan,
1259+
.set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
12271260
};
12281261

12291262
const struct stmmac_ops dwmac510_ops = {
@@ -1277,6 +1310,8 @@ const struct stmmac_ops dwmac510_ops = {
12771310
.add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr,
12781311
.del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr,
12791312
.restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr,
1313+
.rx_hw_vlan = dwmac4_rx_hw_vlan,
1314+
.set_hw_vlan_mode = dwmac4_set_hw_vlan_mode,
12801315
};
12811316

12821317
static u32 dwmac4_get_num_vlan(void __iomem *ioaddr)

drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,17 @@ static int dwmac4_get_tx_ls(struct dma_desc *p)
198198
>> TDES3_LAST_DESCRIPTOR_SHIFT;
199199
}
200200

201+
static u16 dwmac4_wrback_get_rx_vlan_tci(struct dma_desc *p)
202+
{
203+
return (le32_to_cpu(p->des0) & RDES0_VLAN_TAG_MASK);
204+
}
205+
206+
static bool dwmac4_wrback_get_rx_vlan_valid(struct dma_desc *p)
207+
{
208+
return ((le32_to_cpu(p->des3) & RDES3_LAST_DESCRIPTOR) &&
209+
(le32_to_cpu(p->des3) & RDES3_RDES0_VALID));
210+
}
211+
201212
static int dwmac4_wrback_get_rx_frame_len(struct dma_desc *p, int rx_coe)
202213
{
203214
return (le32_to_cpu(p->des3) & RDES3_PACKET_SIZE_MASK);
@@ -551,6 +562,8 @@ const struct stmmac_desc_ops dwmac4_desc_ops = {
551562
.set_tx_owner = dwmac4_set_tx_owner,
552563
.set_rx_owner = dwmac4_set_rx_owner,
553564
.get_tx_ls = dwmac4_get_tx_ls,
565+
.get_rx_vlan_tci = dwmac4_wrback_get_rx_vlan_tci,
566+
.get_rx_vlan_valid = dwmac4_wrback_get_rx_vlan_valid,
554567
.get_rx_frame_len = dwmac4_wrback_get_rx_frame_len,
555568
.enable_tx_timestamp = dwmac4_rd_enable_tx_timestamp,
556569
.get_tx_timestamp_status = dwmac4_wrback_get_tx_timestamp_status,

drivers/net/ethernet/stmicro/stmmac/hwif.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ struct stmmac_desc_ops {
5656
void (*set_tx_ic)(struct dma_desc *p);
5757
/* Last tx segment reports the transmit status */
5858
int (*get_tx_ls)(struct dma_desc *p);
59+
/* Get the tag of the descriptor */
60+
u16 (*get_rx_vlan_tci)(struct dma_desc *p);
61+
/* Get the valid status of descriptor */
62+
bool (*get_rx_vlan_valid)(struct dma_desc *p);
5963
/* Return the transmit status looking at the TDES1 */
6064
int (*tx_status)(struct stmmac_extra_stats *x,
6165
struct dma_desc *p, void __iomem *ioaddr);
@@ -117,6 +121,10 @@ struct stmmac_desc_ops {
117121
stmmac_do_void_callback(__priv, desc, set_tx_ic, __args)
118122
#define stmmac_get_tx_ls(__priv, __args...) \
119123
stmmac_do_callback(__priv, desc, get_tx_ls, __args)
124+
#define stmmac_get_rx_vlan_tci(__priv, __args...) \
125+
stmmac_do_callback(__priv, desc, get_rx_vlan_tci, __args)
126+
#define stmmac_get_rx_vlan_valid(__priv, __args...) \
127+
stmmac_do_callback(__priv, desc, get_rx_vlan_valid, __args)
120128
#define stmmac_tx_status(__priv, __args...) \
121129
stmmac_do_callback(__priv, desc, tx_status, __args)
122130
#define stmmac_get_tx_len(__priv, __args...) \
@@ -388,6 +396,9 @@ struct stmmac_ops {
388396
void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
389397
__le16 perfect_match, bool is_double);
390398
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
399+
void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc,
400+
struct sk_buff *skb);
401+
void (*set_hw_vlan_mode)(struct mac_device_info *hw);
391402
int (*add_hw_vlan_rx_fltr)(struct net_device *dev,
392403
struct mac_device_info *hw,
393404
__be16 proto, u16 vid);
@@ -497,6 +508,10 @@ struct stmmac_ops {
497508
stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args)
498509
#define stmmac_enable_vlan(__priv, __args...) \
499510
stmmac_do_void_callback(__priv, mac, enable_vlan, __args)
511+
#define stmmac_rx_hw_vlan(__priv, __args...) \
512+
stmmac_do_void_callback(__priv, mac, rx_hw_vlan, __args)
513+
#define stmmac_set_hw_vlan_mode(__priv, __args...) \
514+
stmmac_do_void_callback(__priv, mac, set_hw_vlan_mode, __args)
500515
#define stmmac_add_hw_vlan_rx_fltr(__priv, __args...) \
501516
stmmac_do_callback(__priv, mac, add_hw_vlan_rx_fltr, __args)
502517
#define stmmac_del_hw_vlan_rx_fltr(__priv, __args...) \

drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3469,6 +3469,8 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)
34693469
/* Start the ball rolling... */
34703470
stmmac_start_all_dma(priv);
34713471

3472+
stmmac_set_hw_vlan_mode(priv, priv->hw);
3473+
34723474
if (priv->dma_cap.fpesel) {
34733475
stmmac_fpe_start_wq(priv);
34743476

@@ -4993,7 +4995,12 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue,
49934995
}
49944996

49954997
stmmac_get_rx_hwtstamp(priv, p, np, skb);
4996-
stmmac_rx_vlan(priv->dev, skb);
4998+
if (priv->hw->hw_vlan_en)
4999+
/* MAC level stripping. */
5000+
stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
5001+
else
5002+
/* Driver level stripping. */
5003+
stmmac_rx_vlan(priv->dev, skb);
49975004
skb->protocol = eth_type_trans(skb, priv->dev);
49985005

49995006
if (unlikely(!coe))
@@ -5509,7 +5516,14 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
55095516
/* Got entire packet into SKB. Finish it. */
55105517

55115518
stmmac_get_rx_hwtstamp(priv, p, np, skb);
5512-
stmmac_rx_vlan(priv->dev, skb);
5519+
5520+
if (priv->hw->hw_vlan_en)
5521+
/* MAC level stripping. */
5522+
stmmac_rx_hw_vlan(priv, priv->hw, p, skb);
5523+
else
5524+
/* Driver level stripping. */
5525+
stmmac_rx_vlan(priv->dev, skb);
5526+
55135527
skb->protocol = eth_type_trans(skb, priv->dev);
55145528

55155529
if (unlikely(!coe))
@@ -5818,6 +5832,13 @@ static int stmmac_set_features(struct net_device *netdev,
58185832
stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan);
58195833
}
58205834

5835+
if (features & NETIF_F_HW_VLAN_CTAG_RX)
5836+
priv->hw->hw_vlan_en = true;
5837+
else
5838+
priv->hw->hw_vlan_en = false;
5839+
5840+
stmmac_set_hw_vlan_mode(priv, priv->hw);
5841+
58215842
return 0;
58225843
}
58235844

@@ -7509,6 +7530,9 @@ int stmmac_dvr_probe(struct device *device,
75097530
#ifdef STMMAC_VLAN_TAG_USED
75107531
/* Both mac100 and gmac support receive VLAN tag detection */
75117532
ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX;
7533+
ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX;
7534+
priv->hw->hw_vlan_en = true;
7535+
75127536
if (priv->dma_cap.vlhash) {
75137537
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
75147538
ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;

0 commit comments

Comments
 (0)