Skip to content

Commit a3a41d2

Browse files
grygoriySdavem330
authored andcommitted
net: ethernet: ti: cpsw: enable vlan rx vlan offload
In VLAN_AWARE mode CPSW can insert VLAN header encapsulation word on Host port 0 egress (RX) before the packet data if RX_VLAN_ENCAP bit is set in CPSW_CONTROL register. VLAN header encapsulation word has following format: HDR_PKT_Priority bits 29-31 - Header Packet VLAN prio (Highest prio: 7) HDR_PKT_CFI bits 28 - Header Packet VLAN CFI bit. HDR_PKT_Vid bits 27-16 - Header Packet VLAN ID PKT_Type bits 8-9 - Packet Type. Indicates whether the packet is VLAN-tagged, priority-tagged, or non-tagged. 00: VLAN-tagged packet 01: Reserved 10: Priority-tagged packet 11: Non-tagged packet This feature can be used to implement TX VLAN offload in case of VLAN-tagged packets and to insert VLAN tag in case Non-tagged packet was received on port with PVID set. As per documentation, CPSW never modifies packet data on Host egress (RX) and as result, without this feature enabled, Host port will not be able to receive properly packets which entered switch non-tagged through external Port with PVID set (when non-tagged packet forwarded from external Port with PVID set to another external Port - packet will be VLAN tagged properly). Implementation details: - on RX driver will check CPDMA status bit RX_VLAN_ENCAP BIT(19) in CPPI descriptor to identify when VLAN header encapsulation word is present. - PKT_Type = 0x01 or 0x02 then ignore VLAN header encapsulation word and pass packet as is; - if HDR_PKT_Vid = 0 then ignore VLAN header encapsulation word and pass packet as is; - In dual mac mode traffic is separated between ports using default port vlans, which are not be visible to Host and so should not be reported. Hence, check for default port vlans in dual mac mode and ignore VLAN header encapsulation word; - otherwise fill SKB with VLAN info using __vlan_hwaccel_put_tag(); - PKT_Type = 0x00 (VLAN-tagged) then strip out VLAN header from SKB. Signed-off-by: Grygorii Strashko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d7cb444 commit a3a41d2

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-4
lines changed

drivers/net/ethernet/ti/cpsw.c

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,18 @@ do { \
120120
#define CPDMA_RXCP 0x60
121121

122122
#define CPSW_POLL_WEIGHT 64
123+
#define CPSW_RX_VLAN_ENCAP_HDR_SIZE 4
123124
#define CPSW_MIN_PACKET_SIZE (VLAN_ETH_ZLEN)
124-
#define CPSW_MAX_PACKET_SIZE (VLAN_ETH_FRAME_LEN + ETH_FCS_LEN)
125+
#define CPSW_MAX_PACKET_SIZE (VLAN_ETH_FRAME_LEN +\
126+
ETH_FCS_LEN +\
127+
CPSW_RX_VLAN_ENCAP_HDR_SIZE)
125128

126129
#define RX_PRIORITY_MAPPING 0x76543210
127130
#define TX_PRIORITY_MAPPING 0x33221100
128131
#define CPDMA_TX_PRIORITY_MAP 0x01234567
129132

130133
#define CPSW_VLAN_AWARE BIT(1)
134+
#define CPSW_RX_VLAN_ENCAP BIT(2)
131135
#define CPSW_ALE_VLAN_AWARE 1
132136

133137
#define CPSW_FIFO_NORMAL_MODE (0 << 16)
@@ -148,6 +152,18 @@ do { \
148152
#define CPSW_MAX_QUEUES 8
149153
#define CPSW_CPDMA_DESCS_POOL_SIZE_DEFAULT 256
150154

155+
#define CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT 29
156+
#define CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK GENMASK(2, 0)
157+
#define CPSW_RX_VLAN_ENCAP_HDR_VID_SHIFT 16
158+
#define CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_SHIFT 8
159+
#define CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_MSK GENMASK(1, 0)
160+
enum {
161+
CPSW_RX_VLAN_ENCAP_HDR_PKT_VLAN_TAG = 0,
162+
CPSW_RX_VLAN_ENCAP_HDR_PKT_RESERV,
163+
CPSW_RX_VLAN_ENCAP_HDR_PKT_PRIO_TAG,
164+
CPSW_RX_VLAN_ENCAP_HDR_PKT_UNTAG,
165+
};
166+
151167
static int debug_level;
152168
module_param(debug_level, int, 0);
153169
MODULE_PARM_DESC(debug_level, "cpsw debug level (NETIF_MSG bits)");
@@ -718,6 +734,49 @@ static void cpsw_tx_handler(void *token, int len, int status)
718734
dev_kfree_skb_any(skb);
719735
}
720736

737+
static void cpsw_rx_vlan_encap(struct sk_buff *skb)
738+
{
739+
struct cpsw_priv *priv = netdev_priv(skb->dev);
740+
struct cpsw_common *cpsw = priv->cpsw;
741+
u32 rx_vlan_encap_hdr = *((u32 *)skb->data);
742+
u16 vtag, vid, prio, pkt_type;
743+
744+
/* Remove VLAN header encapsulation word */
745+
skb_pull(skb, CPSW_RX_VLAN_ENCAP_HDR_SIZE);
746+
747+
pkt_type = (rx_vlan_encap_hdr >>
748+
CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_SHIFT) &
749+
CPSW_RX_VLAN_ENCAP_HDR_PKT_TYPE_MSK;
750+
/* Ignore unknown & Priority-tagged packets*/
751+
if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_RESERV ||
752+
pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_PRIO_TAG)
753+
return;
754+
755+
vid = (rx_vlan_encap_hdr >>
756+
CPSW_RX_VLAN_ENCAP_HDR_VID_SHIFT) &
757+
VLAN_VID_MASK;
758+
/* Ignore vid 0 and pass packet as is */
759+
if (!vid)
760+
return;
761+
/* Ignore default vlans in dual mac mode */
762+
if (cpsw->data.dual_emac &&
763+
vid == cpsw->slaves[priv->emac_port].port_vlan)
764+
return;
765+
766+
prio = (rx_vlan_encap_hdr >>
767+
CPSW_RX_VLAN_ENCAP_HDR_PRIO_SHIFT) &
768+
CPSW_RX_VLAN_ENCAP_HDR_PRIO_MSK;
769+
770+
vtag = (prio << VLAN_PRIO_SHIFT) | vid;
771+
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vtag);
772+
773+
/* strip vlan tag for VLAN-tagged packet */
774+
if (pkt_type == CPSW_RX_VLAN_ENCAP_HDR_PKT_VLAN_TAG) {
775+
memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN);
776+
skb_pull(skb, VLAN_HLEN);
777+
}
778+
}
779+
721780
static void cpsw_rx_handler(void *token, int len, int status)
722781
{
723782
struct cpdma_chan *ch;
@@ -752,6 +811,8 @@ static void cpsw_rx_handler(void *token, int len, int status)
752811
if (new_skb) {
753812
skb_copy_queue_mapping(new_skb, skb);
754813
skb_put(skb, len);
814+
if (status & CPDMA_RX_VLAN_ENCAP)
815+
cpsw_rx_vlan_encap(skb);
755816
cpts_rx_timestamp(cpsw->cpts, skb);
756817
skb->protocol = eth_type_trans(skb, ndev);
757818
netif_receive_skb(skb);
@@ -1406,7 +1467,7 @@ static void cpsw_init_host_port(struct cpsw_priv *priv)
14061467
cpsw_ale_control_set(cpsw->ale, HOST_PORT_NUM, ALE_VLAN_AWARE,
14071468
CPSW_ALE_VLAN_AWARE);
14081469
control_reg = readl(&cpsw->regs->control);
1409-
control_reg |= CPSW_VLAN_AWARE;
1470+
control_reg |= CPSW_VLAN_AWARE | CPSW_RX_VLAN_ENCAP;
14101471
writel(control_reg, &cpsw->regs->control);
14111472
fifo_mode = (cpsw->data.dual_emac) ? CPSW_FIFO_DUAL_MAC_MODE :
14121473
CPSW_FIFO_NORMAL_MODE;
@@ -3122,7 +3183,7 @@ static int cpsw_probe(struct platform_device *pdev)
31223183
cpsw->quirk_irq = true;
31233184
}
31243185

3125-
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
3186+
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_CTAG_RX;
31263187

31273188
ndev->netdev_ops = &cpsw_netdev_ops;
31283189
ndev->ethtool_ops = &cpsw_ethtool_ops;

drivers/net/ethernet/ti/davinci_cpdma.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1164,7 +1164,7 @@ static int __cpdma_chan_process(struct cpdma_chan *chan)
11641164
outlen -= CPDMA_DESC_CRC_LEN;
11651165

11661166
status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE |
1167-
CPDMA_DESC_PORT_MASK);
1167+
CPDMA_DESC_PORT_MASK | CPDMA_RX_VLAN_ENCAP);
11681168

11691169
chan->head = desc_from_phys(pool, desc_read(desc, hw_next));
11701170
chan_write(chan, cp, desc_dma);

drivers/net/ethernet/ti/davinci_cpdma.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
#define CPDMA_RX_SOURCE_PORT(__status__) ((__status__ >> 16) & 0x7)
2121

22+
#define CPDMA_RX_VLAN_ENCAP BIT(19)
23+
2224
#define CPDMA_EOI_RX_THRESH 0x0
2325
#define CPDMA_EOI_RX 0x1
2426
#define CPDMA_EOI_TX 0x2

0 commit comments

Comments
 (0)