OSDN Git Service

net: dsa: tag_ocelot: convert to tagger-owned data
authorVladimir Oltean <vladimir.oltean@nxp.com>
Thu, 9 Dec 2021 23:34:38 +0000 (01:34 +0200)
committerDavid S. Miller <davem@davemloft.net>
Sun, 12 Dec 2021 12:51:33 +0000 (12:51 +0000)
The felix driver makes very light use of dp->priv, and the tagger is
effectively stateless. dp->priv is practically only needed to set up a
callback to perform deferred xmit of PTP and STP packets using the
ocelot-8021q tagging protocol (the main ocelot tagging protocol makes no
use of dp->priv, although this driver sets up dp->priv irrespective of
actual tagging protocol in use).

struct felix_port (what used to be pointed to by dp->priv) is removed
and replaced with a two-sided structure. The public side of this
structure, visible to the switch driver, is ocelot_8021q_tagger_data.
The private side is ocelot_8021q_tagger_private, and the latter
structure physically encapsulates the former. The public half of the
tagger data structure can be accessed through a helper of the same name
(ocelot_8021q_tagger_data) which also sanity-checks the protocol
currently in use by the switch. The public/private split was requested
by Andrew Lunn.

Suggested-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/ocelot/felix.c
include/linux/dsa/ocelot.h
net/dsa/tag_ocelot_8021q.c

index a02fec3..f4fc403 100644 (file)
@@ -1155,38 +1155,22 @@ static void felix_port_deferred_xmit(struct kthread_work *work)
        kfree(xmit_work);
 }
 
-static int felix_port_setup_tagger_data(struct dsa_switch *ds, int port)
+static int felix_connect_tag_protocol(struct dsa_switch *ds,
+                                     enum dsa_tag_protocol proto)
 {
-       struct dsa_port *dp = dsa_to_port(ds, port);
-       struct ocelot *ocelot = ds->priv;
-       struct felix *felix = ocelot_to_felix(ocelot);
-       struct felix_port *felix_port;
+       struct ocelot_8021q_tagger_data *tagger_data;
 
-       if (!dsa_port_is_user(dp))
+       switch (proto) {
+       case DSA_TAG_PROTO_OCELOT_8021Q:
+               tagger_data = ocelot_8021q_tagger_data(ds);
+               tagger_data->xmit_work_fn = felix_port_deferred_xmit;
                return 0;
-
-       felix_port = kzalloc(sizeof(*felix_port), GFP_KERNEL);
-       if (!felix_port)
-               return -ENOMEM;
-
-       felix_port->xmit_worker = felix->xmit_worker;
-       felix_port->xmit_work_fn = felix_port_deferred_xmit;
-
-       dp->priv = felix_port;
-
-       return 0;
-}
-
-static void felix_port_teardown_tagger_data(struct dsa_switch *ds, int port)
-{
-       struct dsa_port *dp = dsa_to_port(ds, port);
-       struct felix_port *felix_port = dp->priv;
-
-       if (!felix_port)
-               return;
-
-       dp->priv = NULL;
-       kfree(felix_port);
+       case DSA_TAG_PROTO_OCELOT:
+       case DSA_TAG_PROTO_SEVILLE:
+               return 0;
+       default:
+               return -EPROTONOSUPPORT;
+       }
 }
 
 /* Hardware initialization done here so that we can allocate structures with
@@ -1217,12 +1201,6 @@ static int felix_setup(struct dsa_switch *ds)
                }
        }
 
-       felix->xmit_worker = kthread_create_worker(0, "felix_xmit");
-       if (IS_ERR(felix->xmit_worker)) {
-               err = PTR_ERR(felix->xmit_worker);
-               goto out_deinit_timestamp;
-       }
-
        for (port = 0; port < ds->num_ports; port++) {
                if (dsa_is_unused_port(ds, port))
                        continue;
@@ -1233,14 +1211,6 @@ static int felix_setup(struct dsa_switch *ds)
                 * bits of vlan tag.
                 */
                felix_port_qos_map_init(ocelot, port);
-
-               err = felix_port_setup_tagger_data(ds, port);
-               if (err) {
-                       dev_err(ds->dev,
-                               "port %d failed to set up tagger data: %pe\n",
-                               port, ERR_PTR(err));
-                       goto out_deinit_ports;
-               }
        }
 
        err = ocelot_devlink_sb_register(ocelot);
@@ -1268,13 +1238,9 @@ out_deinit_ports:
                if (dsa_is_unused_port(ds, port))
                        continue;
 
-               felix_port_teardown_tagger_data(ds, port);
                ocelot_deinit_port(ocelot, port);
        }
 
-       kthread_destroy_worker(felix->xmit_worker);
-
-out_deinit_timestamp:
        ocelot_deinit_timestamp(ocelot);
        ocelot_deinit(ocelot);
 
@@ -1303,12 +1269,9 @@ static void felix_teardown(struct dsa_switch *ds)
                if (dsa_is_unused_port(ds, port))
                        continue;
 
-               felix_port_teardown_tagger_data(ds, port);
                ocelot_deinit_port(ocelot, port);
        }
 
-       kthread_destroy_worker(felix->xmit_worker);
-
        ocelot_devlink_sb_unregister(ocelot);
        ocelot_deinit_timestamp(ocelot);
        ocelot_deinit(ocelot);
@@ -1648,6 +1611,7 @@ felix_mrp_del_ring_role(struct dsa_switch *ds, int port,
 const struct dsa_switch_ops felix_switch_ops = {
        .get_tag_protocol               = felix_get_tag_protocol,
        .change_tag_protocol            = felix_change_tag_protocol,
+       .connect_tag_protocol           = felix_connect_tag_protocol,
        .setup                          = felix_setup,
        .teardown                       = felix_teardown,
        .set_ageing_time                = felix_set_ageing_time,
index 7ee708a..dca2969 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/kthread.h>
 #include <linux/packing.h>
 #include <linux/skbuff.h>
+#include <net/dsa.h>
 
 struct ocelot_skb_cb {
        struct sk_buff *clone;
@@ -168,11 +169,18 @@ struct felix_deferred_xmit_work {
        struct kthread_work work;
 };
 
-struct felix_port {
+struct ocelot_8021q_tagger_data {
        void (*xmit_work_fn)(struct kthread_work *work);
-       struct kthread_worker *xmit_worker;
 };
 
+static inline struct ocelot_8021q_tagger_data *
+ocelot_8021q_tagger_data(struct dsa_switch *ds)
+{
+       BUG_ON(ds->dst->tag_ops->proto != DSA_TAG_PROTO_OCELOT_8021Q);
+
+       return ds->tagger_data;
+}
+
 static inline void ocelot_xfh_get_rew_val(void *extraction, u64 *rew_val)
 {
        packing(extraction, rew_val, 116, 85, OCELOT_TAG_LEN, UNPACK, 0);
index a1919ea..fe451f4 100644 (file)
 #include <linux/dsa/ocelot.h>
 #include "dsa_priv.h"
 
+struct ocelot_8021q_tagger_private {
+       struct ocelot_8021q_tagger_data data; /* Must be first */
+       struct kthread_worker *xmit_worker;
+};
+
 static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp,
                                         struct sk_buff *skb)
 {
+       struct ocelot_8021q_tagger_private *priv = dp->ds->tagger_data;
+       struct ocelot_8021q_tagger_data *data = &priv->data;
+       void (*xmit_work_fn)(struct kthread_work *work);
        struct felix_deferred_xmit_work *xmit_work;
-       struct felix_port *felix_port = dp->priv;
+       struct kthread_worker *xmit_worker;
+
+       xmit_work_fn = data->xmit_work_fn;
+       xmit_worker = priv->xmit_worker;
+
+       if (!xmit_work_fn || !xmit_worker)
+               return NULL;
 
        xmit_work = kzalloc(sizeof(*xmit_work), GFP_ATOMIC);
        if (!xmit_work)
                return NULL;
 
        /* Calls felix_port_deferred_xmit in felix.c */
-       kthread_init_work(&xmit_work->work, felix_port->xmit_work_fn);
+       kthread_init_work(&xmit_work->work, xmit_work_fn);
        /* Increase refcount so the kfree_skb in dsa_slave_xmit
         * won't really free the packet.
         */
        xmit_work->dp = dp;
        xmit_work->skb = skb_get(skb);
 
-       kthread_queue_work(felix_port->xmit_worker, &xmit_work->work);
+       kthread_queue_work(xmit_worker, &xmit_work->work);
 
        return NULL;
 }
@@ -67,11 +81,64 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
        return skb;
 }
 
+static void ocelot_disconnect(struct dsa_switch_tree *dst)
+{
+       struct ocelot_8021q_tagger_private *priv;
+       struct dsa_port *dp;
+
+       list_for_each_entry(dp, &dst->ports, list) {
+               priv = dp->ds->tagger_data;
+
+               if (!priv)
+                       continue;
+
+               if (priv->xmit_worker)
+                       kthread_destroy_worker(priv->xmit_worker);
+
+               kfree(priv);
+               dp->ds->tagger_data = NULL;
+       }
+}
+
+static int ocelot_connect(struct dsa_switch_tree *dst)
+{
+       struct ocelot_8021q_tagger_private *priv;
+       struct dsa_port *dp;
+       int err;
+
+       list_for_each_entry(dp, &dst->ports, list) {
+               if (dp->ds->tagger_data)
+                       continue;
+
+               priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+               if (!priv) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               priv->xmit_worker = kthread_create_worker(0, "felix_xmit");
+               if (IS_ERR(priv->xmit_worker)) {
+                       err = PTR_ERR(priv->xmit_worker);
+                       goto out;
+               }
+
+               dp->ds->tagger_data = priv;
+       }
+
+       return 0;
+
+out:
+       ocelot_disconnect(dst);
+       return err;
+}
+
 static const struct dsa_device_ops ocelot_8021q_netdev_ops = {
        .name                   = "ocelot-8021q",
        .proto                  = DSA_TAG_PROTO_OCELOT_8021Q,
        .xmit                   = ocelot_xmit,
        .rcv                    = ocelot_rcv,
+       .connect                = ocelot_connect,
+       .disconnect             = ocelot_disconnect,
        .needed_headroom        = VLAN_HLEN,
        .promisc_on_master      = true,
 };