mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 02:36:02 +00:00
net: dsa: tag_ocelot: convert to tagger-owned data
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>
This commit is contained in:
parent
dc452a471d
commit
35d9768021
@ -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 @@ static int felix_setup(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);
|
||||
|
||||
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,
|
||||
|
@ -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);
|
||||
|
@ -12,25 +12,39 @@
|
||||
#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,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user