Skip to content

Commit bccf56c

Browse files
committed
Merge branch 'dsa-bridge-tx-forwarding-offload-fixes-part-1'
Vladimir Oltean says: ==================== DSA bridge TX forwarding offload fixes - part 1 This is part 1 of a series of fixes to the bridge TX forwarding offload feature introduced for v5.15. Sadly, the other fixes are so intrusive that they cannot be reasonably be sent to the "net" tree, as they also include API changes. So they are left as part 2 for net-next. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 1b1499a + 5bded82 commit bccf56c

File tree

8 files changed

+153
-35
lines changed

8 files changed

+153
-35
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11153,6 +11153,7 @@ S: Maintained
1115311153
F: Documentation/devicetree/bindings/net/dsa/marvell.txt
1115411154
F: Documentation/networking/devlink/mv88e6xxx.rst
1115511155
F: drivers/net/dsa/mv88e6xxx/
11156+
F: include/linux/dsa/mv88e6xxx.h
1115611157
F: include/linux/platform_data/mv88e6xxx.h
1115711158

1115811159
MARVELL ARMADA 3700 PHY DRIVERS

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 97 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <linux/bitfield.h>
1414
#include <linux/delay.h>
15+
#include <linux/dsa/mv88e6xxx.h>
1516
#include <linux/etherdevice.h>
1617
#include <linux/ethtool.h>
1718
#include <linux/if_bridge.h>
@@ -1677,6 +1678,30 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port,
16771678
return 0;
16781679
}
16791680

1681+
static int mv88e6xxx_port_commit_pvid(struct mv88e6xxx_chip *chip, int port)
1682+
{
1683+
struct dsa_port *dp = dsa_to_port(chip->ds, port);
1684+
struct mv88e6xxx_port *p = &chip->ports[port];
1685+
u16 pvid = MV88E6XXX_VID_STANDALONE;
1686+
bool drop_untagged = false;
1687+
int err;
1688+
1689+
if (dp->bridge_dev) {
1690+
if (br_vlan_enabled(dp->bridge_dev)) {
1691+
pvid = p->bridge_pvid.vid;
1692+
drop_untagged = !p->bridge_pvid.valid;
1693+
} else {
1694+
pvid = MV88E6XXX_VID_BRIDGED;
1695+
}
1696+
}
1697+
1698+
err = mv88e6xxx_port_set_pvid(chip, port, pvid);
1699+
if (err)
1700+
return err;
1701+
1702+
return mv88e6xxx_port_drop_untagged(chip, port, drop_untagged);
1703+
}
1704+
16801705
static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
16811706
bool vlan_filtering,
16821707
struct netlink_ext_ack *extack)
@@ -1690,7 +1715,16 @@ static int mv88e6xxx_port_vlan_filtering(struct dsa_switch *ds, int port,
16901715
return -EOPNOTSUPP;
16911716

16921717
mv88e6xxx_reg_lock(chip);
1718+
16931719
err = mv88e6xxx_port_set_8021q_mode(chip, port, mode);
1720+
if (err)
1721+
goto unlock;
1722+
1723+
err = mv88e6xxx_port_commit_pvid(chip, port);
1724+
if (err)
1725+
goto unlock;
1726+
1727+
unlock:
16941728
mv88e6xxx_reg_unlock(chip);
16951729

16961730
return err;
@@ -1725,11 +1759,15 @@ static int mv88e6xxx_port_db_load_purge(struct mv88e6xxx_chip *chip, int port,
17251759
u16 fid;
17261760
int err;
17271761

1728-
/* Null VLAN ID corresponds to the port private database */
1762+
/* Ports have two private address databases: one for when the port is
1763+
* standalone and one for when the port is under a bridge and the
1764+
* 802.1Q mode is disabled. When the port is standalone, DSA wants its
1765+
* address database to remain 100% empty, so we never load an ATU entry
1766+
* into a standalone port's database. Therefore, translate the null
1767+
* VLAN ID into the port's database used for VLAN-unaware bridging.
1768+
*/
17291769
if (vid == 0) {
1730-
err = mv88e6xxx_port_get_fid(chip, port, &fid);
1731-
if (err)
1732-
return err;
1770+
fid = MV88E6XXX_FID_BRIDGED;
17331771
} else {
17341772
err = mv88e6xxx_vtu_get(chip, vid, &vlan);
17351773
if (err)
@@ -2123,6 +2161,7 @@ static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
21232161
struct mv88e6xxx_chip *chip = ds->priv;
21242162
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
21252163
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
2164+
struct mv88e6xxx_port *p = &chip->ports[port];
21262165
bool warn;
21272166
u8 member;
21282167
int err;
@@ -2156,13 +2195,21 @@ static int mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
21562195
}
21572196

21582197
if (pvid) {
2159-
err = mv88e6xxx_port_set_pvid(chip, port, vlan->vid);
2160-
if (err) {
2161-
dev_err(ds->dev, "p%d: failed to set PVID %d\n",
2162-
port, vlan->vid);
2198+
p->bridge_pvid.vid = vlan->vid;
2199+
p->bridge_pvid.valid = true;
2200+
2201+
err = mv88e6xxx_port_commit_pvid(chip, port);
2202+
if (err)
2203+
goto out;
2204+
} else if (vlan->vid && p->bridge_pvid.vid == vlan->vid) {
2205+
/* The old pvid was reinstalled as a non-pvid VLAN */
2206+
p->bridge_pvid.valid = false;
2207+
2208+
err = mv88e6xxx_port_commit_pvid(chip, port);
2209+
if (err)
21632210
goto out;
2164-
}
21652211
}
2212+
21662213
out:
21672214
mv88e6xxx_reg_unlock(chip);
21682215

@@ -2212,6 +2259,7 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
22122259
const struct switchdev_obj_port_vlan *vlan)
22132260
{
22142261
struct mv88e6xxx_chip *chip = ds->priv;
2262+
struct mv88e6xxx_port *p = &chip->ports[port];
22152263
int err = 0;
22162264
u16 pvid;
22172265

@@ -2229,7 +2277,9 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
22292277
goto unlock;
22302278

22312279
if (vlan->vid == pvid) {
2232-
err = mv88e6xxx_port_set_pvid(chip, port, 0);
2280+
p->bridge_pvid.valid = false;
2281+
2282+
err = mv88e6xxx_port_commit_pvid(chip, port);
22332283
if (err)
22342284
goto unlock;
22352285
}
@@ -2393,7 +2443,16 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
23932443
int err;
23942444

23952445
mv88e6xxx_reg_lock(chip);
2446+
23962447
err = mv88e6xxx_bridge_map(chip, br);
2448+
if (err)
2449+
goto unlock;
2450+
2451+
err = mv88e6xxx_port_commit_pvid(chip, port);
2452+
if (err)
2453+
goto unlock;
2454+
2455+
unlock:
23972456
mv88e6xxx_reg_unlock(chip);
23982457

23992458
return err;
@@ -2403,11 +2462,20 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
24032462
struct net_device *br)
24042463
{
24052464
struct mv88e6xxx_chip *chip = ds->priv;
2465+
int err;
24062466

24072467
mv88e6xxx_reg_lock(chip);
2468+
24082469
if (mv88e6xxx_bridge_map(chip, br) ||
24092470
mv88e6xxx_port_vlan_map(chip, port))
24102471
dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");
2472+
2473+
err = mv88e6xxx_port_commit_pvid(chip, port);
2474+
if (err)
2475+
dev_err(ds->dev,
2476+
"port %d failed to restore standalone pvid: %pe\n",
2477+
port, ERR_PTR(err));
2478+
24112479
mv88e6xxx_reg_unlock(chip);
24122480
}
24132481

@@ -2853,6 +2921,20 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
28532921
if (err)
28542922
return err;
28552923

2924+
/* Associate MV88E6XXX_VID_BRIDGED with MV88E6XXX_FID_BRIDGED in the
2925+
* ATU by virtue of the fact that mv88e6xxx_atu_new() will pick it as
2926+
* the first free FID after MV88E6XXX_FID_STANDALONE. This will be used
2927+
* as the private PVID on ports under a VLAN-unaware bridge.
2928+
* Shared (DSA and CPU) ports must also be members of it, to translate
2929+
* the VID from the DSA tag into MV88E6XXX_FID_BRIDGED, instead of
2930+
* relying on their port default FID.
2931+
*/
2932+
err = mv88e6xxx_port_vlan_join(chip, port, MV88E6XXX_VID_BRIDGED,
2933+
MV88E6XXX_G1_VTU_DATA_MEMBER_TAG_UNTAGGED,
2934+
false);
2935+
if (err)
2936+
return err;
2937+
28562938
if (chip->info->ops->port_set_jumbo_size) {
28572939
err = chip->info->ops->port_set_jumbo_size(chip, port, 10218);
28582940
if (err)
@@ -2925,7 +3007,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
29253007
* database, and allow bidirectional communication between the
29263008
* CPU and DSA port(s), and the other ports.
29273009
*/
2928-
err = mv88e6xxx_port_set_fid(chip, port, 0);
3010+
err = mv88e6xxx_port_set_fid(chip, port, MV88E6XXX_FID_STANDALONE);
29293011
if (err)
29303012
return err;
29313013

@@ -3115,6 +3197,10 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
31153197
}
31163198
}
31173199

3200+
err = mv88e6xxx_vtu_setup(chip);
3201+
if (err)
3202+
goto unlock;
3203+
31183204
/* Setup Switch Port Registers */
31193205
for (i = 0; i < mv88e6xxx_num_ports(chip); i++) {
31203206
if (dsa_is_unused_port(ds, i))
@@ -3144,10 +3230,6 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
31443230
if (err)
31453231
goto unlock;
31463232

3147-
err = mv88e6xxx_vtu_setup(chip);
3148-
if (err)
3149-
goto unlock;
3150-
31513233
err = mv88e6xxx_pvt_setup(chip);
31523234
if (err)
31533235
goto unlock;

drivers/net/dsa/mv88e6xxx/chip.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
#define EDSA_HLEN 8
2222
#define MV88E6XXX_N_FID 4096
2323

24+
#define MV88E6XXX_FID_STANDALONE 0
25+
#define MV88E6XXX_FID_BRIDGED 1
26+
2427
/* PVT limits for 4-bit port and 5-bit switch */
2528
#define MV88E6XXX_MAX_PVT_SWITCHES 32
2629
#define MV88E6XXX_MAX_PVT_PORTS 16
@@ -246,9 +249,15 @@ struct mv88e6xxx_policy {
246249
u16 vid;
247250
};
248251

252+
struct mv88e6xxx_vlan {
253+
u16 vid;
254+
bool valid;
255+
};
256+
249257
struct mv88e6xxx_port {
250258
struct mv88e6xxx_chip *chip;
251259
int port;
260+
struct mv88e6xxx_vlan bridge_pvid;
252261
u64 serdes_stats[2];
253262
u64 atu_member_violation;
254263
u64 atu_miss_violation;

drivers/net/dsa/mv88e6xxx/port.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,27 @@ int mv88e6xxx_port_set_8021q_mode(struct mv88e6xxx_chip *chip, int port,
12571257
return 0;
12581258
}
12591259

1260+
int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
1261+
bool drop_untagged)
1262+
{
1263+
u16 old, new;
1264+
int err;
1265+
1266+
err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL2, &old);
1267+
if (err)
1268+
return err;
1269+
1270+
if (drop_untagged)
1271+
new = old | MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;
1272+
else
1273+
new = old & ~MV88E6XXX_PORT_CTL2_DISCARD_UNTAGGED;
1274+
1275+
if (new == old)
1276+
return 0;
1277+
1278+
return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, new);
1279+
}
1280+
12601281
int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port)
12611282
{
12621283
u16 reg;

drivers/net/dsa/mv88e6xxx/port.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,8 @@ int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
423423
phy_interface_t mode);
424424
int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
425425
int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode);
426+
int mv88e6xxx_port_drop_untagged(struct mv88e6xxx_chip *chip, int port,
427+
bool drop_untagged);
426428
int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port);
427429
int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port,
428430
int upstream_port);

include/linux/dsa/mv88e6xxx.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* SPDX-License-Identifier: GPL-2.0
2+
* Copyright 2021 NXP
3+
*/
4+
5+
#ifndef _NET_DSA_TAG_MV88E6XXX_H
6+
#define _NET_DSA_TAG_MV88E6XXX_H
7+
8+
#include <linux/if_vlan.h>
9+
10+
#define MV88E6XXX_VID_STANDALONE 0
11+
#define MV88E6XXX_VID_BRIDGED (VLAN_N_VID - 1)
12+
13+
#endif

net/dsa/dsa2.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num)
170170
/* Check if the bridge is still in use, otherwise it is time
171171
* to clean it up so we can reuse this bridge_num later.
172172
*/
173-
if (!dsa_bridge_num_find(bridge_dev))
173+
if (dsa_bridge_num_find(bridge_dev) < 0)
174174
clear_bit(bridge_num, &dsa_fwd_offloading_bridges);
175175
}
176176

net/dsa/tag_dsa.c

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
* 6 6 2 2 4 2 N
4646
*/
4747

48+
#include <linux/dsa/mv88e6xxx.h>
4849
#include <linux/etherdevice.h>
4950
#include <linux/list.h>
5051
#include <linux/slab.h>
@@ -129,12 +130,9 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
129130
u8 tag_dev, tag_port;
130131
enum dsa_cmd cmd;
131132
u8 *dsa_header;
132-
u16 pvid = 0;
133-
int err;
134133

135134
if (skb->offload_fwd_mark) {
136135
struct dsa_switch_tree *dst = dp->ds->dst;
137-
struct net_device *br = dp->bridge_dev;
138136

139137
cmd = DSA_CMD_FORWARD;
140138

@@ -144,19 +142,6 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
144142
*/
145143
tag_dev = dst->last_switch + 1 + dp->bridge_num;
146144
tag_port = 0;
147-
148-
/* If we are offloading forwarding for a VLAN-unaware bridge,
149-
* inject packets to hardware using the bridge's pvid, since
150-
* that's where the packets ingressed from.
151-
*/
152-
if (!br_vlan_enabled(br)) {
153-
/* Safe because __dev_queue_xmit() runs under
154-
* rcu_read_lock_bh()
155-
*/
156-
err = br_vlan_get_pvid_rcu(br, &pvid);
157-
if (err)
158-
return NULL;
159-
}
160145
} else {
161146
cmd = DSA_CMD_FROM_CPU;
162147
tag_dev = dp->ds->index;
@@ -180,16 +165,21 @@ static struct sk_buff *dsa_xmit_ll(struct sk_buff *skb, struct net_device *dev,
180165
dsa_header[2] &= ~0x10;
181166
}
182167
} else {
168+
struct net_device *br = dp->bridge_dev;
169+
u16 vid;
170+
171+
vid = br ? MV88E6XXX_VID_BRIDGED : MV88E6XXX_VID_STANDALONE;
172+
183173
skb_push(skb, DSA_HLEN + extra);
184174
dsa_alloc_etype_header(skb, DSA_HLEN + extra);
185175

186-
/* Construct untagged DSA tag. */
176+
/* Construct DSA header from untagged frame. */
187177
dsa_header = dsa_etype_header_pos_tx(skb) + extra;
188178

189179
dsa_header[0] = (cmd << 6) | tag_dev;
190180
dsa_header[1] = tag_port << 3;
191-
dsa_header[2] = pvid >> 8;
192-
dsa_header[3] = pvid & 0xff;
181+
dsa_header[2] = vid >> 8;
182+
dsa_header[3] = vid & 0xff;
193183
}
194184

195185
return skb;

0 commit comments

Comments
 (0)