Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright 2020-2021 NXP
0003  *
0004  * An implementation of the software-defined tag_8021q.c tagger format, which
0005  * also preserves full functionality under a vlan_filtering bridge. It does
0006  * this by using the TCAM engines for:
0007  * - pushing the RX VLAN as a second, outer tag, on egress towards the CPU port
0008  * - redirecting towards the correct front port based on TX VLAN and popping
0009  *   that on egress
0010  */
0011 #include <linux/dsa/8021q.h>
0012 #include <linux/dsa/ocelot.h>
0013 #include "dsa_priv.h"
0014 
0015 struct ocelot_8021q_tagger_private {
0016     struct ocelot_8021q_tagger_data data; /* Must be first */
0017     struct kthread_worker *xmit_worker;
0018 };
0019 
0020 static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp,
0021                      struct sk_buff *skb)
0022 {
0023     struct ocelot_8021q_tagger_private *priv = dp->ds->tagger_data;
0024     struct ocelot_8021q_tagger_data *data = &priv->data;
0025     void (*xmit_work_fn)(struct kthread_work *work);
0026     struct felix_deferred_xmit_work *xmit_work;
0027     struct kthread_worker *xmit_worker;
0028 
0029     xmit_work_fn = data->xmit_work_fn;
0030     xmit_worker = priv->xmit_worker;
0031 
0032     if (!xmit_work_fn || !xmit_worker)
0033         return NULL;
0034 
0035     /* PTP over IP packets need UDP checksumming. We may have inherited
0036      * NETIF_F_HW_CSUM from the DSA master, but these packets are not sent
0037      * through the DSA master, so calculate the checksum here.
0038      */
0039     if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
0040         return NULL;
0041 
0042     xmit_work = kzalloc(sizeof(*xmit_work), GFP_ATOMIC);
0043     if (!xmit_work)
0044         return NULL;
0045 
0046     /* Calls felix_port_deferred_xmit in felix.c */
0047     kthread_init_work(&xmit_work->work, xmit_work_fn);
0048     /* Increase refcount so the kfree_skb in dsa_slave_xmit
0049      * won't really free the packet.
0050      */
0051     xmit_work->dp = dp;
0052     xmit_work->skb = skb_get(skb);
0053 
0054     kthread_queue_work(xmit_worker, &xmit_work->work);
0055 
0056     return NULL;
0057 }
0058 
0059 static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
0060                    struct net_device *netdev)
0061 {
0062     struct dsa_port *dp = dsa_slave_to_port(netdev);
0063     u16 queue_mapping = skb_get_queue_mapping(skb);
0064     u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
0065     u16 tx_vid = dsa_tag_8021q_standalone_vid(dp);
0066     struct ethhdr *hdr = eth_hdr(skb);
0067 
0068     if (ocelot_ptp_rew_op(skb) || is_link_local_ether_addr(hdr->h_dest))
0069         return ocelot_defer_xmit(dp, skb);
0070 
0071     return dsa_8021q_xmit(skb, netdev, ETH_P_8021Q,
0072                   ((pcp << VLAN_PRIO_SHIFT) | tx_vid));
0073 }
0074 
0075 static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
0076                   struct net_device *netdev)
0077 {
0078     int src_port, switch_id;
0079 
0080     dsa_8021q_rcv(skb, &src_port, &switch_id, NULL);
0081 
0082     skb->dev = dsa_master_find_slave(netdev, switch_id, src_port);
0083     if (!skb->dev)
0084         return NULL;
0085 
0086     dsa_default_offload_fwd_mark(skb);
0087 
0088     return skb;
0089 }
0090 
0091 static void ocelot_disconnect(struct dsa_switch *ds)
0092 {
0093     struct ocelot_8021q_tagger_private *priv = ds->tagger_data;
0094 
0095     kthread_destroy_worker(priv->xmit_worker);
0096     kfree(priv);
0097     ds->tagger_data = NULL;
0098 }
0099 
0100 static int ocelot_connect(struct dsa_switch *ds)
0101 {
0102     struct ocelot_8021q_tagger_private *priv;
0103     int err;
0104 
0105     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0106     if (!priv)
0107         return -ENOMEM;
0108 
0109     priv->xmit_worker = kthread_create_worker(0, "felix_xmit");
0110     if (IS_ERR(priv->xmit_worker)) {
0111         err = PTR_ERR(priv->xmit_worker);
0112         kfree(priv);
0113         return err;
0114     }
0115 
0116     ds->tagger_data = priv;
0117 
0118     return 0;
0119 }
0120 
0121 static const struct dsa_device_ops ocelot_8021q_netdev_ops = {
0122     .name           = "ocelot-8021q",
0123     .proto          = DSA_TAG_PROTO_OCELOT_8021Q,
0124     .xmit           = ocelot_xmit,
0125     .rcv            = ocelot_rcv,
0126     .connect        = ocelot_connect,
0127     .disconnect     = ocelot_disconnect,
0128     .needed_headroom    = VLAN_HLEN,
0129     .promisc_on_master  = true,
0130 };
0131 
0132 MODULE_LICENSE("GPL v2");
0133 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_OCELOT_8021Q);
0134 
0135 module_dsa_tag_driver(ocelot_8021q_netdev_ops);