1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2020-2021 NXP
4 * An implementation of the software-defined tag_8021q.c tagger format, which
5 * also preserves full functionality under a vlan_filtering bridge. It does
6 * this by using the TCAM engines for:
7 * - pushing the RX VLAN as a second, outer tag, on egress towards the CPU port
8 * - redirecting towards the correct front port based on TX VLAN and popping
11 #include <linux/dsa/8021q.h>
12 #include <linux/dsa/ocelot.h>
15 static struct sk_buff
*ocelot_defer_xmit(struct dsa_port
*dp
,
18 struct felix_deferred_xmit_work
*xmit_work
;
19 struct felix_port
*felix_port
= dp
->priv
;
21 xmit_work
= kzalloc(sizeof(*xmit_work
), GFP_ATOMIC
);
25 /* Calls felix_port_deferred_xmit in felix.c */
26 kthread_init_work(&xmit_work
->work
, felix_port
->xmit_work_fn
);
27 /* Increase refcount so the kfree_skb in dsa_slave_xmit
28 * won't really free the packet.
31 xmit_work
->skb
= skb_get(skb
);
33 kthread_queue_work(felix_port
->xmit_worker
, &xmit_work
->work
);
38 static struct sk_buff
*ocelot_xmit(struct sk_buff
*skb
,
39 struct net_device
*netdev
)
41 struct dsa_port
*dp
= dsa_slave_to_port(netdev
);
42 u16 tx_vid
= dsa_8021q_tx_vid(dp
->ds
, dp
->index
);
43 u16 queue_mapping
= skb_get_queue_mapping(skb
);
44 u8 pcp
= netdev_txq_to_tc(netdev
, queue_mapping
);
45 struct ethhdr
*hdr
= eth_hdr(skb
);
47 if (ocelot_ptp_rew_op(skb
) || is_link_local_ether_addr(hdr
->h_dest
))
48 return ocelot_defer_xmit(dp
, skb
);
50 return dsa_8021q_xmit(skb
, netdev
, ETH_P_8021Q
,
51 ((pcp
<< VLAN_PRIO_SHIFT
) | tx_vid
));
54 static struct sk_buff
*ocelot_rcv(struct sk_buff
*skb
,
55 struct net_device
*netdev
)
57 int src_port
, switch_id
;
59 dsa_8021q_rcv(skb
, &src_port
, &switch_id
);
61 skb
->dev
= dsa_master_find_slave(netdev
, switch_id
, src_port
);
65 dsa_default_offload_fwd_mark(skb
);
70 static const struct dsa_device_ops ocelot_8021q_netdev_ops
= {
71 .name
= "ocelot-8021q",
72 .proto
= DSA_TAG_PROTO_OCELOT_8021Q
,
75 .needed_headroom
= VLAN_HLEN
,
76 .promisc_on_master
= true,
79 MODULE_LICENSE("GPL v2");
80 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT_8021Q
);
82 module_dsa_tag_driver(ocelot_8021q_netdev_ops
);