Commit 30d93227 authored by Jose Abreu's avatar Jose Abreu Committed by David S. Miller

net: stmmac: Add support for VLAN Insertion Offload

Adds the logic to insert a given VLAN ID in a packet. This is offloaded
to HW and its descriptor based. For now, only XGMAC implements the
necessary callbacks.
Signed-off-by: default avatarJose Abreu <joabreu@synopsys.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 81b945ae
...@@ -358,6 +358,8 @@ struct dma_features { ...@@ -358,6 +358,8 @@ struct dma_features {
unsigned int rssen; unsigned int rssen;
unsigned int vlhash; unsigned int vlhash;
unsigned int sphen; unsigned int sphen;
unsigned int vlins;
unsigned int dvlan;
}; };
/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ /* GMAC TX FIFO is 8K, Rx FIFO is 16K */
...@@ -389,6 +391,12 @@ struct dma_features { ...@@ -389,6 +391,12 @@ struct dma_features {
#define STMMAC_RSS_HASH_KEY_SIZE 40 #define STMMAC_RSS_HASH_KEY_SIZE 40
#define STMMAC_RSS_MAX_TABLE_SIZE 256 #define STMMAC_RSS_MAX_TABLE_SIZE 256
/* VLAN */
#define STMMAC_VLAN_NONE 0x0
#define STMMAC_VLAN_REMOVE 0x1
#define STMMAC_VLAN_INSERT 0x2
#define STMMAC_VLAN_REPLACE 0x3
extern const struct stmmac_desc_ops enh_desc_ops; extern const struct stmmac_desc_ops enh_desc_ops;
extern const struct stmmac_desc_ops ndesc_ops; extern const struct stmmac_desc_ops ndesc_ops;
......
...@@ -63,6 +63,11 @@ ...@@ -63,6 +63,11 @@
#define XGMAC_VLAN_ETV BIT(16) #define XGMAC_VLAN_ETV BIT(16)
#define XGMAC_VLAN_VID GENMASK(15, 0) #define XGMAC_VLAN_VID GENMASK(15, 0)
#define XGMAC_VLAN_HASH_TABLE 0x00000058 #define XGMAC_VLAN_HASH_TABLE 0x00000058
#define XGMAC_VLAN_INCL 0x00000060
#define XGMAC_VLAN_VLTI BIT(20)
#define XGMAC_VLAN_CSVL BIT(19)
#define XGMAC_VLAN_VLC GENMASK(17, 16)
#define XGMAC_VLAN_VLC_SHIFT 16
#define XGMAC_RXQ_CTRL0 0x000000a0 #define XGMAC_RXQ_CTRL0 0x000000a0
#define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2) #define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2)
#define XGMAC_RXQEN_SHIFT(x) ((x) * 2) #define XGMAC_RXQEN_SHIFT(x) ((x) * 2)
...@@ -128,6 +133,7 @@ ...@@ -128,6 +133,7 @@
#define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0) #define XGMAC_HWFEAT_RXQCNT GENMASK(3, 0)
#define XGMAC_HW_FEATURE3 0x00000128 #define XGMAC_HW_FEATURE3 0x00000128
#define XGMAC_HWFEAT_ASP GENMASK(15, 14) #define XGMAC_HWFEAT_ASP GENMASK(15, 14)
#define XGMAC_HWFEAT_DVLAN BIT(13)
#define XGMAC_HWFEAT_FRPES GENMASK(12, 11) #define XGMAC_HWFEAT_FRPES GENMASK(12, 11)
#define XGMAC_HWFEAT_FRPPB GENMASK(10, 9) #define XGMAC_HWFEAT_FRPPB GENMASK(10, 9)
#define XGMAC_HWFEAT_FRPSEL BIT(3) #define XGMAC_HWFEAT_FRPSEL BIT(3)
...@@ -337,10 +343,14 @@ ...@@ -337,10 +343,14 @@
#define XGMAC_REGSIZE ((0x0000317c + (0x80 * 15)) / 4) #define XGMAC_REGSIZE ((0x0000317c + (0x80 * 15)) / 4)
/* Descriptors */ /* Descriptors */
#define XGMAC_TDES2_IVT GENMASK(31, 16)
#define XGMAC_TDES2_IVT_SHIFT 16
#define XGMAC_TDES2_IOC BIT(31) #define XGMAC_TDES2_IOC BIT(31)
#define XGMAC_TDES2_TTSE BIT(30) #define XGMAC_TDES2_TTSE BIT(30)
#define XGMAC_TDES2_B2L GENMASK(29, 16) #define XGMAC_TDES2_B2L GENMASK(29, 16)
#define XGMAC_TDES2_B2L_SHIFT 16 #define XGMAC_TDES2_B2L_SHIFT 16
#define XGMAC_TDES2_VTIR GENMASK(15, 14)
#define XGMAC_TDES2_VTIR_SHIFT 14
#define XGMAC_TDES2_B1L GENMASK(13, 0) #define XGMAC_TDES2_B1L GENMASK(13, 0)
#define XGMAC_TDES3_OWN BIT(31) #define XGMAC_TDES3_OWN BIT(31)
#define XGMAC_TDES3_CTXT BIT(30) #define XGMAC_TDES3_CTXT BIT(30)
...@@ -353,10 +363,15 @@ ...@@ -353,10 +363,15 @@
#define XGMAC_TDES3_SAIC_SHIFT 23 #define XGMAC_TDES3_SAIC_SHIFT 23
#define XGMAC_TDES3_THL GENMASK(22, 19) #define XGMAC_TDES3_THL GENMASK(22, 19)
#define XGMAC_TDES3_THL_SHIFT 19 #define XGMAC_TDES3_THL_SHIFT 19
#define XGMAC_TDES3_IVTIR GENMASK(19, 18)
#define XGMAC_TDES3_IVTIR_SHIFT 18
#define XGMAC_TDES3_TSE BIT(18) #define XGMAC_TDES3_TSE BIT(18)
#define XGMAC_TDES3_IVLTV BIT(17)
#define XGMAC_TDES3_CIC GENMASK(17, 16) #define XGMAC_TDES3_CIC GENMASK(17, 16)
#define XGMAC_TDES3_CIC_SHIFT 16 #define XGMAC_TDES3_CIC_SHIFT 16
#define XGMAC_TDES3_TPL GENMASK(17, 0) #define XGMAC_TDES3_TPL GENMASK(17, 0)
#define XGMAC_TDES3_VLTV BIT(16)
#define XGMAC_TDES3_VT GENMASK(15, 0)
#define XGMAC_TDES3_FL GENMASK(14, 0) #define XGMAC_TDES3_FL GENMASK(14, 0)
#define XGMAC_RDES2_HL GENMASK(9, 0) #define XGMAC_RDES2_HL GENMASK(9, 0)
#define XGMAC_RDES3_OWN BIT(31) #define XGMAC_RDES3_OWN BIT(31)
......
...@@ -1150,6 +1150,19 @@ static void dwxgmac2_sarc_configure(void __iomem *ioaddr, int val) ...@@ -1150,6 +1150,19 @@ static void dwxgmac2_sarc_configure(void __iomem *ioaddr, int val)
writel(value, ioaddr + XGMAC_TX_CONFIG); writel(value, ioaddr + XGMAC_TX_CONFIG);
} }
static void dwxgmac2_enable_vlan(struct mac_device_info *hw, u32 type)
{
void __iomem *ioaddr = hw->pcsr;
u32 value;
value = readl(ioaddr + XGMAC_VLAN_INCL);
value |= XGMAC_VLAN_VLTI;
value |= XGMAC_VLAN_CSVL; /* Only use SVLAN */
value &= ~XGMAC_VLAN_VLC;
value |= (type << XGMAC_VLAN_VLC_SHIFT) & XGMAC_VLAN_VLC;
writel(value, ioaddr + XGMAC_VLAN_INCL);
}
const struct stmmac_ops dwxgmac210_ops = { const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init, .core_init = dwxgmac2_core_init,
.set_mac = dwxgmac2_set_mac, .set_mac = dwxgmac2_set_mac,
...@@ -1189,6 +1202,7 @@ const struct stmmac_ops dwxgmac210_ops = { ...@@ -1189,6 +1202,7 @@ const struct stmmac_ops dwxgmac210_ops = {
.get_mac_tx_timestamp = dwxgmac2_get_mac_tx_timestamp, .get_mac_tx_timestamp = dwxgmac2_get_mac_tx_timestamp,
.flex_pps_config = dwxgmac2_flex_pps_config, .flex_pps_config = dwxgmac2_flex_pps_config,
.sarc_configure = dwxgmac2_sarc_configure, .sarc_configure = dwxgmac2_sarc_configure,
.enable_vlan = dwxgmac2_enable_vlan,
}; };
int dwxgmac2_setup(struct stmmac_priv *priv) int dwxgmac2_setup(struct stmmac_priv *priv)
......
...@@ -305,6 +305,39 @@ static void dwxgmac2_set_sarc(struct dma_desc *p, u32 sarc_type) ...@@ -305,6 +305,39 @@ static void dwxgmac2_set_sarc(struct dma_desc *p, u32 sarc_type)
p->des3 |= cpu_to_le32(sarc_type & XGMAC_TDES3_SAIC); p->des3 |= cpu_to_le32(sarc_type & XGMAC_TDES3_SAIC);
} }
static void dwxgmac2_set_vlan_tag(struct dma_desc *p, u16 tag, u16 inner_tag,
u32 inner_type)
{
p->des0 = 0;
p->des1 = 0;
p->des2 = 0;
p->des3 = 0;
/* Inner VLAN */
if (inner_type) {
u32 des = inner_tag << XGMAC_TDES2_IVT_SHIFT;
des &= XGMAC_TDES2_IVT;
p->des2 = cpu_to_le32(des);
des = inner_type << XGMAC_TDES3_IVTIR_SHIFT;
des &= XGMAC_TDES3_IVTIR;
p->des3 = cpu_to_le32(des | XGMAC_TDES3_IVLTV);
}
/* Outer VLAN */
p->des3 |= cpu_to_le32(tag & XGMAC_TDES3_VT);
p->des3 |= cpu_to_le32(XGMAC_TDES3_VLTV);
p->des3 |= cpu_to_le32(XGMAC_TDES3_CTXT);
}
static void dwxgmac2_set_vlan(struct dma_desc *p, u32 type)
{
type <<= XGMAC_TDES2_VTIR_SHIFT;
p->des2 |= cpu_to_le32(type & XGMAC_TDES2_VTIR);
}
const struct stmmac_desc_ops dwxgmac210_desc_ops = { const struct stmmac_desc_ops dwxgmac210_desc_ops = {
.tx_status = dwxgmac2_get_tx_status, .tx_status = dwxgmac2_get_tx_status,
.rx_status = dwxgmac2_get_rx_status, .rx_status = dwxgmac2_get_rx_status,
...@@ -332,4 +365,6 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = { ...@@ -332,4 +365,6 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = {
.get_rx_header_len = dwxgmac2_get_rx_header_len, .get_rx_header_len = dwxgmac2_get_rx_header_len,
.set_sec_addr = dwxgmac2_set_sec_addr, .set_sec_addr = dwxgmac2_set_sec_addr,
.set_sarc = dwxgmac2_set_sarc, .set_sarc = dwxgmac2_set_sarc,
.set_vlan_tag = dwxgmac2_set_vlan_tag,
.set_vlan = dwxgmac2_set_vlan,
}; };
...@@ -359,6 +359,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr, ...@@ -359,6 +359,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature 0 */ /* MAC HW feature 0 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0); hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0);
dma_cap->vlins = (hw_cap & XGMAC_HWFEAT_SAVLANINS) >> 27;
dma_cap->rx_coe = (hw_cap & XGMAC_HWFEAT_RXCOESEL) >> 16; dma_cap->rx_coe = (hw_cap & XGMAC_HWFEAT_RXCOESEL) >> 16;
dma_cap->tx_coe = (hw_cap & XGMAC_HWFEAT_TXCOESEL) >> 14; dma_cap->tx_coe = (hw_cap & XGMAC_HWFEAT_TXCOESEL) >> 14;
dma_cap->eee = (hw_cap & XGMAC_HWFEAT_EEESEL) >> 13; dma_cap->eee = (hw_cap & XGMAC_HWFEAT_EEESEL) >> 13;
...@@ -413,6 +414,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr, ...@@ -413,6 +414,7 @@ static void dwxgmac2_get_hw_feature(void __iomem *ioaddr,
/* MAC HW feature 3 */ /* MAC HW feature 3 */
hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3); hw_cap = readl(ioaddr + XGMAC_HW_FEATURE3);
dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14; dma_cap->asp = (hw_cap & XGMAC_HWFEAT_ASP) >> 14;
dma_cap->dvlan = (hw_cap & XGMAC_HWFEAT_DVLAN) >> 13;
dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11; dma_cap->frpes = (hw_cap & XGMAC_HWFEAT_FRPES) >> 11;
dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9; dma_cap->frpbs = (hw_cap & XGMAC_HWFEAT_FRPPB) >> 9;
dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3; dma_cap->frpsel = (hw_cap & XGMAC_HWFEAT_FRPSEL) >> 3;
......
...@@ -92,6 +92,9 @@ struct stmmac_desc_ops { ...@@ -92,6 +92,9 @@ struct stmmac_desc_ops {
int (*get_rx_header_len)(struct dma_desc *p, unsigned int *len); int (*get_rx_header_len)(struct dma_desc *p, unsigned int *len);
void (*set_sec_addr)(struct dma_desc *p, dma_addr_t addr); void (*set_sec_addr)(struct dma_desc *p, dma_addr_t addr);
void (*set_sarc)(struct dma_desc *p, u32 sarc_type); void (*set_sarc)(struct dma_desc *p, u32 sarc_type);
void (*set_vlan_tag)(struct dma_desc *p, u16 tag, u16 inner_tag,
u32 inner_type);
void (*set_vlan)(struct dma_desc *p, u32 type);
}; };
#define stmmac_init_rx_desc(__priv, __args...) \ #define stmmac_init_rx_desc(__priv, __args...) \
...@@ -150,6 +153,10 @@ struct stmmac_desc_ops { ...@@ -150,6 +153,10 @@ struct stmmac_desc_ops {
stmmac_do_void_callback(__priv, desc, set_sec_addr, __args) stmmac_do_void_callback(__priv, desc, set_sec_addr, __args)
#define stmmac_set_desc_sarc(__priv, __args...) \ #define stmmac_set_desc_sarc(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, set_sarc, __args) stmmac_do_void_callback(__priv, desc, set_sarc, __args)
#define stmmac_set_desc_vlan_tag(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, set_vlan_tag, __args)
#define stmmac_set_desc_vlan(__priv, __args...) \
stmmac_do_void_callback(__priv, desc, set_vlan, __args)
struct stmmac_dma_cfg; struct stmmac_dma_cfg;
struct dma_features; struct dma_features;
...@@ -351,6 +358,7 @@ struct stmmac_ops { ...@@ -351,6 +358,7 @@ struct stmmac_ops {
/* VLAN */ /* VLAN */
void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash, void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash,
bool is_double); bool is_double);
void (*enable_vlan)(struct mac_device_info *hw, u32 type);
/* TX Timestamp */ /* TX Timestamp */
int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts); int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts);
/* Source Address Insertion / Replacement */ /* Source Address Insertion / Replacement */
...@@ -429,6 +437,8 @@ struct stmmac_ops { ...@@ -429,6 +437,8 @@ struct stmmac_ops {
stmmac_do_callback(__priv, mac, rss_configure, __args) stmmac_do_callback(__priv, mac, rss_configure, __args)
#define stmmac_update_vlan_hash(__priv, __args...) \ #define stmmac_update_vlan_hash(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args) stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args)
#define stmmac_enable_vlan(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, enable_vlan, __args)
#define stmmac_get_mac_tx_timestamp(__priv, __args...) \ #define stmmac_get_mac_tx_timestamp(__priv, __args...) \
stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args) stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args)
#define stmmac_sarc_configure(__priv, __args...) \ #define stmmac_sarc_configure(__priv, __args...) \
......
...@@ -2617,6 +2617,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp) ...@@ -2617,6 +2617,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
stmmac_enable_sph(priv, priv->ioaddr, 1, chan); stmmac_enable_sph(priv, priv->ioaddr, 1, chan);
} }
/* VLAN Tag Insertion */
if (priv->dma_cap.vlins)
stmmac_enable_vlan(priv, priv->hw, STMMAC_VLAN_INSERT);
/* Start the ball rolling... */ /* Start the ball rolling... */
stmmac_start_all_dma(priv); stmmac_start_all_dma(priv);
...@@ -2794,6 +2798,33 @@ static int stmmac_release(struct net_device *dev) ...@@ -2794,6 +2798,33 @@ static int stmmac_release(struct net_device *dev)
return 0; return 0;
} }
static bool stmmac_vlan_insert(struct stmmac_priv *priv, struct sk_buff *skb,
struct stmmac_tx_queue *tx_q)
{
u16 tag = 0x0, inner_tag = 0x0;
u32 inner_type = 0x0;
struct dma_desc *p;
if (!priv->dma_cap.vlins)
return false;
if (!skb_vlan_tag_present(skb))
return false;
if (skb->vlan_proto == htons(ETH_P_8021AD)) {
inner_tag = skb_vlan_tag_get(skb);
inner_type = STMMAC_VLAN_INSERT;
}
tag = skb_vlan_tag_get(skb);
p = tx_q->dma_tx + tx_q->cur_tx;
if (stmmac_set_desc_vlan_tag(priv, p, tag, inner_tag, inner_type))
return false;
stmmac_set_tx_owner(priv, p);
tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, DMA_TX_SIZE);
return true;
}
/** /**
* stmmac_tso_allocator - close entry point of the driver * stmmac_tso_allocator - close entry point of the driver
* @priv: driver private structure * @priv: driver private structure
...@@ -2873,12 +2904,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2873,12 +2904,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev); struct stmmac_priv *priv = netdev_priv(dev);
int nfrags = skb_shinfo(skb)->nr_frags; int nfrags = skb_shinfo(skb)->nr_frags;
u32 queue = skb_get_queue_mapping(skb); u32 queue = skb_get_queue_mapping(skb);
unsigned int first_entry;
struct stmmac_tx_queue *tx_q; struct stmmac_tx_queue *tx_q;
unsigned int first_entry;
int tmp_pay_len = 0; int tmp_pay_len = 0;
u32 pay_len, mss; u32 pay_len, mss;
u8 proto_hdr_len; u8 proto_hdr_len;
dma_addr_t des; dma_addr_t des;
bool has_vlan;
int i; int i;
tx_q = &priv->tx_queue[queue]; tx_q = &priv->tx_queue[queue];
...@@ -2920,12 +2952,18 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -2920,12 +2952,18 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev)
skb->data_len); skb->data_len);
} }
/* Check if VLAN can be inserted by HW */
has_vlan = stmmac_vlan_insert(priv, skb, tx_q);
first_entry = tx_q->cur_tx; first_entry = tx_q->cur_tx;
WARN_ON(tx_q->tx_skbuff[first_entry]); WARN_ON(tx_q->tx_skbuff[first_entry]);
desc = tx_q->dma_tx + first_entry; desc = tx_q->dma_tx + first_entry;
first = desc; first = desc;
if (has_vlan)
stmmac_set_desc_vlan(priv, first, STMMAC_VLAN_INSERT);
/* first descriptor: fill Headers on Buf1 */ /* first descriptor: fill Headers on Buf1 */
des = dma_map_single(priv->device, skb->data, skb_headlen(skb), des = dma_map_single(priv->device, skb->data, skb_headlen(skb),
DMA_TO_DEVICE); DMA_TO_DEVICE);
...@@ -3085,6 +3123,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3085,6 +3123,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int first_entry; unsigned int first_entry;
unsigned int enh_desc; unsigned int enh_desc;
dma_addr_t des; dma_addr_t des;
bool has_vlan;
int entry; int entry;
tx_q = &priv->tx_queue[queue]; tx_q = &priv->tx_queue[queue];
...@@ -3110,6 +3149,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3110,6 +3149,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
/* Check if VLAN can be inserted by HW */
has_vlan = stmmac_vlan_insert(priv, skb, tx_q);
entry = tx_q->cur_tx; entry = tx_q->cur_tx;
first_entry = entry; first_entry = entry;
WARN_ON(tx_q->tx_skbuff[first_entry]); WARN_ON(tx_q->tx_skbuff[first_entry]);
...@@ -3123,6 +3165,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3123,6 +3165,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
first = desc; first = desc;
if (has_vlan)
stmmac_set_desc_vlan(priv, first, STMMAC_VLAN_INSERT);
enh_desc = priv->plat->enh_desc; enh_desc = priv->plat->enh_desc;
/* To program the descriptors according to the size of the frame */ /* To program the descriptors according to the size of the frame */
if (enh_desc) if (enh_desc)
...@@ -4473,6 +4518,11 @@ int stmmac_dvr_probe(struct device *device, ...@@ -4473,6 +4518,11 @@ int stmmac_dvr_probe(struct device *device,
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER; ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER;
} }
if (priv->dma_cap.vlins) {
ndev->features |= NETIF_F_HW_VLAN_CTAG_TX;
if (priv->dma_cap.dvlan)
ndev->features |= NETIF_F_HW_VLAN_STAG_TX;
}
#endif #endif
priv->msg_enable = netif_msg_init(debug, default_msg_level); priv->msg_enable = netif_msg_init(debug, default_msg_level);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment