Skip to content

Commit 5899ee3

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: tag_8021q: add a context structure
While working on another tag_8021q driver implementation, some things became apparent: - It is not mandatory for a DSA driver to offload the tag_8021q VLANs by using the VLAN table per se. For example, it can add custom TCAM rules that simply encapsulate RX traffic, and redirect & decapsulate rules for TX traffic. For such a driver, it makes no sense to receive the tag_8021q configuration through the same callback as it receives the VLAN configuration from the bridge and the 8021q modules. - Currently, sja1105 (the only tag_8021q user) sets a priv->expect_dsa_8021q variable to distinguish between the bridge calling, and tag_8021q calling. That can be improved, to say the least. - The crosschip bridging operations are, in fact, stateful already. The list of crosschip_links must be kept by the caller and passed to the relevant tag_8021q functions. So it would be nice if the tag_8021q configuration was more self-contained. This patch attempts to do that. Create a struct dsa_8021q_context which encapsulates a struct dsa_switch, and has 2 function pointers for adding and deleting a VLAN. These will replace the previous channel to the driver, which was through the .port_vlan_add and .port_vlan_del callbacks of dsa_switch_ops. Also put the list of crosschip_links into this dsa_8021q_context. Drivers that don't support cross-chip bridging can simply omit to initialize this list, as long as they dont call any cross-chip function. The sja1105_vlan_add and sja1105_vlan_del functions are refactored into a smaller sja1105_vlan_add_one, which now has 2 entry points: - sja1105_vlan_add, from struct dsa_switch_ops - sja1105_dsa_8021q_vlan_add, from the tag_8021q ops But even this change is fairly trivial. It just reflects the fact that for sja1105, the VLANs from these 2 channels end up in the same hardware table. However that is not necessarily true in the general sense (and that's the reason for making this change). The rest of the patch is mostly plain refactoring of "ds" -> "ctx". The dsa_8021q_context structure needs to be propagated because adding a VLAN is now done through the ops function pointers inside of it. Signed-off-by: Vladimir Oltean <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7e092af commit 5899ee3

File tree

4 files changed

+216
-173
lines changed

4 files changed

+216
-173
lines changed

drivers/net/dsa/sja1105/sja1105.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,13 @@ struct sja1105_private {
210210
struct dsa_switch *ds;
211211
struct list_head dsa_8021q_vlans;
212212
struct list_head bridge_vlans;
213-
struct list_head crosschip_links;
214213
struct sja1105_flow_block flow_block;
215214
struct sja1105_port ports[SJA1105_NUM_PORTS];
216215
/* Serializes transmission of management frames so that
217216
* the switch doesn't confuse them with one another.
218217
*/
219218
struct mutex mgmt_lock;
220-
bool expect_dsa_8021q;
219+
struct dsa_8021q_context *dsa_8021q_ctx;
221220
enum sja1105_vlan_state vlan_state;
222221
struct sja1105_cbs_entry *cbs;
223222
struct sja1105_tagger_data tagger_data;

drivers/net/dsa/sja1105/sja1105_main.c

Lines changed: 125 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1880,19 +1880,17 @@ static int sja1105_crosschip_bridge_join(struct dsa_switch *ds,
18801880
if (dsa_to_port(ds, port)->bridge_dev != br)
18811881
continue;
18821882

1883-
other_priv->expect_dsa_8021q = true;
1884-
rc = dsa_8021q_crosschip_bridge_join(ds, port, other_ds,
1885-
other_port,
1886-
&priv->crosschip_links);
1887-
other_priv->expect_dsa_8021q = false;
1883+
rc = dsa_8021q_crosschip_bridge_join(priv->dsa_8021q_ctx,
1884+
port,
1885+
other_priv->dsa_8021q_ctx,
1886+
other_port);
18881887
if (rc)
18891888
return rc;
18901889

1891-
priv->expect_dsa_8021q = true;
1892-
rc = dsa_8021q_crosschip_bridge_join(other_ds, other_port, ds,
1893-
port,
1894-
&other_priv->crosschip_links);
1895-
priv->expect_dsa_8021q = false;
1890+
rc = dsa_8021q_crosschip_bridge_join(other_priv->dsa_8021q_ctx,
1891+
other_port,
1892+
priv->dsa_8021q_ctx,
1893+
port);
18961894
if (rc)
18971895
return rc;
18981896
}
@@ -1919,15 +1917,13 @@ static void sja1105_crosschip_bridge_leave(struct dsa_switch *ds,
19191917
if (dsa_to_port(ds, port)->bridge_dev != br)
19201918
continue;
19211919

1922-
other_priv->expect_dsa_8021q = true;
1923-
dsa_8021q_crosschip_bridge_leave(ds, port, other_ds, other_port,
1924-
&priv->crosschip_links);
1925-
other_priv->expect_dsa_8021q = false;
1920+
dsa_8021q_crosschip_bridge_leave(priv->dsa_8021q_ctx, port,
1921+
other_priv->dsa_8021q_ctx,
1922+
other_port);
19261923

1927-
priv->expect_dsa_8021q = true;
1928-
dsa_8021q_crosschip_bridge_leave(other_ds, other_port, ds, port,
1929-
&other_priv->crosschip_links);
1930-
priv->expect_dsa_8021q = false;
1924+
dsa_8021q_crosschip_bridge_leave(other_priv->dsa_8021q_ctx,
1925+
other_port,
1926+
priv->dsa_8021q_ctx, port);
19311927
}
19321928
}
19331929

@@ -1936,7 +1932,7 @@ static int sja1105_setup_8021q_tagging(struct dsa_switch *ds, bool enabled)
19361932
struct sja1105_private *priv = ds->priv;
19371933
int rc;
19381934

1939-
rc = dsa_8021q_setup(priv->ds, enabled);
1935+
rc = dsa_8021q_setup(priv->dsa_8021q_ctx, enabled);
19401936
if (rc)
19411937
return rc;
19421938

@@ -2142,12 +2138,12 @@ struct sja1105_crosschip_vlan {
21422138
bool untagged;
21432139
int port;
21442140
int other_port;
2145-
struct dsa_switch *other_ds;
2141+
struct dsa_8021q_context *other_ctx;
21462142
};
21472143

21482144
struct sja1105_crosschip_switch {
21492145
struct list_head list;
2150-
struct dsa_switch *other_ds;
2146+
struct dsa_8021q_context *other_ctx;
21512147
};
21522148

21532149
static int sja1105_commit_pvid(struct sja1105_private *priv)
@@ -2323,8 +2319,8 @@ sja1105_build_crosschip_subvlans(struct sja1105_private *priv,
23232319

23242320
INIT_LIST_HEAD(&crosschip_vlans);
23252321

2326-
list_for_each_entry(c, &priv->crosschip_links, list) {
2327-
struct sja1105_private *other_priv = c->other_ds->priv;
2322+
list_for_each_entry(c, &priv->dsa_8021q_ctx->crosschip_links, list) {
2323+
struct sja1105_private *other_priv = c->other_ctx->ds->priv;
23282324

23292325
if (other_priv->vlan_state == SJA1105_VLAN_FILTERING_FULL)
23302326
continue;
@@ -2334,7 +2330,7 @@ sja1105_build_crosschip_subvlans(struct sja1105_private *priv,
23342330
*/
23352331
if (!dsa_is_user_port(priv->ds, c->port))
23362332
continue;
2337-
if (!dsa_is_user_port(c->other_ds, c->other_port))
2333+
if (!dsa_is_user_port(c->other_ctx->ds, c->other_port))
23382334
continue;
23392335

23402336
/* Search for VLANs on the remote port */
@@ -2369,7 +2365,7 @@ sja1105_build_crosschip_subvlans(struct sja1105_private *priv,
23692365
tmp->untagged == v->untagged &&
23702366
tmp->port == c->port &&
23712367
tmp->other_port == v->port &&
2372-
tmp->other_ds == c->other_ds) {
2368+
tmp->other_ctx == c->other_ctx) {
23732369
already_added = true;
23742370
break;
23752371
}
@@ -2387,14 +2383,14 @@ sja1105_build_crosschip_subvlans(struct sja1105_private *priv,
23872383
tmp->vid = v->vid;
23882384
tmp->port = c->port;
23892385
tmp->other_port = v->port;
2390-
tmp->other_ds = c->other_ds;
2386+
tmp->other_ctx = c->other_ctx;
23912387
tmp->untagged = v->untagged;
23922388
list_add(&tmp->list, &crosschip_vlans);
23932389
}
23942390
}
23952391

23962392
list_for_each_entry(tmp, &crosschip_vlans, list) {
2397-
struct sja1105_private *other_priv = tmp->other_ds->priv;
2393+
struct sja1105_private *other_priv = tmp->other_ctx->ds->priv;
23982394
int upstream = dsa_upstream_port(priv->ds, tmp->port);
23992395
int match, subvlan;
24002396
u16 rx_vid;
@@ -2411,7 +2407,7 @@ sja1105_build_crosschip_subvlans(struct sja1105_private *priv,
24112407
goto out;
24122408
}
24132409

2414-
rx_vid = dsa_8021q_rx_vid_subvlan(tmp->other_ds,
2410+
rx_vid = dsa_8021q_rx_vid_subvlan(tmp->other_ctx->ds,
24152411
tmp->other_port,
24162412
subvlan);
24172413

@@ -2486,11 +2482,11 @@ static int sja1105_notify_crosschip_switches(struct sja1105_private *priv)
24862482

24872483
INIT_LIST_HEAD(&crosschip_switches);
24882484

2489-
list_for_each_entry(c, &priv->crosschip_links, list) {
2485+
list_for_each_entry(c, &priv->dsa_8021q_ctx->crosschip_links, list) {
24902486
bool already_added = false;
24912487

24922488
list_for_each_entry(s, &crosschip_switches, list) {
2493-
if (s->other_ds == c->other_ds) {
2489+
if (s->other_ctx == c->other_ctx) {
24942490
already_added = true;
24952491
break;
24962492
}
@@ -2505,12 +2501,12 @@ static int sja1105_notify_crosschip_switches(struct sja1105_private *priv)
25052501
rc = -ENOMEM;
25062502
goto out;
25072503
}
2508-
s->other_ds = c->other_ds;
2504+
s->other_ctx = c->other_ctx;
25092505
list_add(&s->list, &crosschip_switches);
25102506
}
25112507

25122508
list_for_each_entry(s, &crosschip_switches, list) {
2513-
struct sja1105_private *other_priv = s->other_ds->priv;
2509+
struct sja1105_private *other_priv = s->other_ctx->ds->priv;
25142510

25152511
rc = sja1105_build_vlan_table(other_priv, false);
25162512
if (rc)
@@ -2611,16 +2607,6 @@ static int sja1105_build_vlan_table(struct sja1105_private *priv, bool notify)
26112607
return rc;
26122608
}
26132609

2614-
/* Select the list to which we should add this VLAN. */
2615-
static struct list_head *sja1105_classify_vlan(struct sja1105_private *priv,
2616-
u16 vid)
2617-
{
2618-
if (priv->expect_dsa_8021q)
2619-
return &priv->dsa_8021q_vlans;
2620-
2621-
return &priv->bridge_vlans;
2622-
}
2623-
26242610
static int sja1105_vlan_prepare(struct dsa_switch *ds, int port,
26252611
const struct switchdev_obj_port_vlan *vlan)
26262612
{
@@ -2635,7 +2621,7 @@ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port,
26352621
* configuration done by dsa_8021q.
26362622
*/
26372623
for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
2638-
if (!priv->expect_dsa_8021q && vid_is_dsa_8021q(vid)) {
2624+
if (vid_is_dsa_8021q(vid)) {
26392625
dev_err(ds->dev, "Range 1024-3071 reserved for dsa_8021q operation\n");
26402626
return -EBUSY;
26412627
}
@@ -2755,6 +2741,54 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
27552741
return sja1105_setup_8021q_tagging(ds, want_tagging);
27562742
}
27572743

2744+
/* Returns number of VLANs added (0 or 1) on success,
2745+
* or a negative error code.
2746+
*/
2747+
static int sja1105_vlan_add_one(struct dsa_switch *ds, int port, u16 vid,
2748+
u16 flags, struct list_head *vlan_list)
2749+
{
2750+
bool untagged = flags & BRIDGE_VLAN_INFO_UNTAGGED;
2751+
bool pvid = flags & BRIDGE_VLAN_INFO_PVID;
2752+
struct sja1105_bridge_vlan *v;
2753+
2754+
list_for_each_entry(v, vlan_list, list)
2755+
if (v->port == port && v->vid == vid &&
2756+
v->untagged == untagged && v->pvid == pvid)
2757+
/* Already added */
2758+
return 0;
2759+
2760+
v = kzalloc(sizeof(*v), GFP_KERNEL);
2761+
if (!v) {
2762+
dev_err(ds->dev, "Out of memory while storing VLAN\n");
2763+
return -ENOMEM;
2764+
}
2765+
2766+
v->port = port;
2767+
v->vid = vid;
2768+
v->untagged = untagged;
2769+
v->pvid = pvid;
2770+
list_add(&v->list, vlan_list);
2771+
2772+
return 1;
2773+
}
2774+
2775+
/* Returns number of VLANs deleted (0 or 1) */
2776+
static int sja1105_vlan_del_one(struct dsa_switch *ds, int port, u16 vid,
2777+
struct list_head *vlan_list)
2778+
{
2779+
struct sja1105_bridge_vlan *v, *n;
2780+
2781+
list_for_each_entry_safe(v, n, vlan_list, list) {
2782+
if (v->port == port && v->vid == vid) {
2783+
list_del(&v->list);
2784+
kfree(v);
2785+
return 1;
2786+
}
2787+
}
2788+
2789+
return 0;
2790+
}
2791+
27582792
static void sja1105_vlan_add(struct dsa_switch *ds, int port,
27592793
const struct switchdev_obj_port_vlan *vlan)
27602794
{
@@ -2764,38 +2798,12 @@ static void sja1105_vlan_add(struct dsa_switch *ds, int port,
27642798
int rc;
27652799

27662800
for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
2767-
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
2768-
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
2769-
struct sja1105_bridge_vlan *v;
2770-
struct list_head *vlan_list;
2771-
bool already_added = false;
2772-
2773-
vlan_list = sja1105_classify_vlan(priv, vid);
2774-
2775-
list_for_each_entry(v, vlan_list, list) {
2776-
if (v->port == port && v->vid == vid &&
2777-
v->untagged == untagged && v->pvid == pvid) {
2778-
already_added = true;
2779-
break;
2780-
}
2781-
}
2782-
2783-
if (already_added)
2784-
continue;
2785-
2786-
v = kzalloc(sizeof(*v), GFP_KERNEL);
2787-
if (!v) {
2788-
dev_err(ds->dev, "Out of memory while storing VLAN\n");
2801+
rc = sja1105_vlan_add_one(ds, port, vid, vlan->flags,
2802+
&priv->bridge_vlans);
2803+
if (rc < 0)
27892804
return;
2790-
}
2791-
2792-
v->port = port;
2793-
v->vid = vid;
2794-
v->untagged = untagged;
2795-
v->pvid = pvid;
2796-
list_add(&v->list, vlan_list);
2797-
2798-
vlan_table_changed = true;
2805+
if (rc > 0)
2806+
vlan_table_changed = true;
27992807
}
28002808

28012809
if (!vlan_table_changed)
@@ -2812,21 +2820,12 @@ static int sja1105_vlan_del(struct dsa_switch *ds, int port,
28122820
struct sja1105_private *priv = ds->priv;
28132821
bool vlan_table_changed = false;
28142822
u16 vid;
2823+
int rc;
28152824

28162825
for (vid = vlan->vid_begin; vid <= vlan->vid_end; vid++) {
2817-
struct sja1105_bridge_vlan *v, *n;
2818-
struct list_head *vlan_list;
2819-
2820-
vlan_list = sja1105_classify_vlan(priv, vid);
2821-
2822-
list_for_each_entry_safe(v, n, vlan_list, list) {
2823-
if (v->port == port && v->vid == vid) {
2824-
list_del(&v->list);
2825-
kfree(v);
2826-
vlan_table_changed = true;
2827-
break;
2828-
}
2829-
}
2826+
rc = sja1105_vlan_del_one(ds, port, vid, &priv->bridge_vlans);
2827+
if (rc > 0)
2828+
vlan_table_changed = true;
28302829
}
28312830

28322831
if (!vlan_table_changed)
@@ -2835,6 +2834,36 @@ static int sja1105_vlan_del(struct dsa_switch *ds, int port,
28352834
return sja1105_build_vlan_table(priv, true);
28362835
}
28372836

2837+
static int sja1105_dsa_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid,
2838+
u16 flags)
2839+
{
2840+
struct sja1105_private *priv = ds->priv;
2841+
int rc;
2842+
2843+
rc = sja1105_vlan_add_one(ds, port, vid, flags, &priv->dsa_8021q_vlans);
2844+
if (rc <= 0)
2845+
return rc;
2846+
2847+
return sja1105_build_vlan_table(priv, true);
2848+
}
2849+
2850+
static int sja1105_dsa_8021q_vlan_del(struct dsa_switch *ds, int port, u16 vid)
2851+
{
2852+
struct sja1105_private *priv = ds->priv;
2853+
int rc;
2854+
2855+
rc = sja1105_vlan_del_one(ds, port, vid, &priv->dsa_8021q_vlans);
2856+
if (!rc)
2857+
return 0;
2858+
2859+
return sja1105_build_vlan_table(priv, true);
2860+
}
2861+
2862+
static const struct dsa_8021q_ops sja1105_dsa_8021q_ops = {
2863+
.vlan_add = sja1105_dsa_8021q_vlan_add,
2864+
.vlan_del = sja1105_dsa_8021q_vlan_del,
2865+
};
2866+
28382867
static int sja1105_best_effort_vlan_filtering_get(struct sja1105_private *priv,
28392868
bool *be_vlan)
28402869
{
@@ -3497,7 +3526,15 @@ static int sja1105_probe(struct spi_device *spi)
34973526
mutex_init(&priv->ptp_data.lock);
34983527
mutex_init(&priv->mgmt_lock);
34993528

3500-
INIT_LIST_HEAD(&priv->crosschip_links);
3529+
priv->dsa_8021q_ctx = devm_kzalloc(dev, sizeof(*priv->dsa_8021q_ctx),
3530+
GFP_KERNEL);
3531+
if (!priv->dsa_8021q_ctx)
3532+
return -ENOMEM;
3533+
3534+
priv->dsa_8021q_ctx->ops = &sja1105_dsa_8021q_ops;
3535+
priv->dsa_8021q_ctx->ds = ds;
3536+
3537+
INIT_LIST_HEAD(&priv->dsa_8021q_ctx->crosschip_links);
35013538
INIT_LIST_HEAD(&priv->bridge_vlans);
35023539
INIT_LIST_HEAD(&priv->dsa_8021q_vlans);
35033540

0 commit comments

Comments
 (0)