summaryrefslogtreecommitdiff
path: root/net/dsa
diff options
context:
space:
mode:
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/dsa2.c19
-rw-r--r--net/dsa/slave.c4
-rw-r--r--net/dsa/tag_8021q.c1
-rw-r--r--net/dsa/tag_ksz.c1
-rw-r--r--net/dsa/tag_ocelot.c39
-rw-r--r--net/dsa/tag_rtl4_a.c2
6 files changed, 48 insertions, 18 deletions
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index da18094b5a04..691d27498b24 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -850,10 +850,6 @@ static int dsa_switch_setup(struct dsa_switch *ds)
dl_priv = devlink_priv(ds->devlink);
dl_priv->ds = ds;
- err = devlink_register(ds->devlink);
- if (err)
- goto free_devlink;
-
/* Setup devlink port instances now, so that the switch
* setup() can register regions etc, against the ports
*/
@@ -879,8 +875,6 @@ static int dsa_switch_setup(struct dsa_switch *ds)
if (err)
goto teardown;
- devlink_params_publish(ds->devlink);
-
if (!ds->slave_mii_bus && ds->ops->phy_read) {
ds->slave_mii_bus = mdiobus_alloc();
if (!ds->slave_mii_bus) {
@@ -896,7 +890,7 @@ static int dsa_switch_setup(struct dsa_switch *ds)
}
ds->setup = true;
-
+ devlink_register(ds->devlink);
return 0;
free_slave_mii_bus:
@@ -911,11 +905,8 @@ unregister_devlink_ports:
list_for_each_entry(dp, &ds->dst->ports, list)
if (dp->ds == ds)
dsa_port_devlink_teardown(dp);
- devlink_unregister(ds->devlink);
-free_devlink:
devlink_free(ds->devlink);
ds->devlink = NULL;
-
return err;
}
@@ -926,22 +917,24 @@ static void dsa_switch_teardown(struct dsa_switch *ds)
if (!ds->setup)
return;
+ if (ds->devlink)
+ devlink_unregister(ds->devlink);
+
if (ds->slave_mii_bus && ds->ops->phy_read) {
mdiobus_unregister(ds->slave_mii_bus);
mdiobus_free(ds->slave_mii_bus);
ds->slave_mii_bus = NULL;
}
- dsa_switch_unregister_notifier(ds);
-
if (ds->ops->teardown)
ds->ops->teardown(ds);
+ dsa_switch_unregister_notifier(ds);
+
if (ds->devlink) {
list_for_each_entry(dp, &ds->dst->ports, list)
if (dp->ds == ds)
dsa_port_devlink_teardown(dp);
- devlink_unregister(ds->devlink);
devlink_free(ds->devlink);
ds->devlink = NULL;
}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index a2bf2d8ac65b..11ec9e689589 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -174,7 +174,7 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
dev_uc_del(master, dev->dev_addr);
out:
- ether_addr_copy(dev->dev_addr, addr->sa_data);
+ eth_hw_addr_set(dev, addr->sa_data);
return 0;
}
@@ -1954,7 +1954,7 @@ int dsa_slave_create(struct dsa_port *port)
slave_dev->ethtool_ops = &dsa_slave_ethtool_ops;
if (!is_zero_ether_addr(port->mac))
- ether_addr_copy(slave_dev->dev_addr, port->mac);
+ eth_hw_addr_set(slave_dev, port->mac);
else
eth_hw_addr_inherit(slave_dev, master);
slave_dev->priv_flags |= IFF_NO_QUEUE;
diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c
index f8f7b7c34e7d..935d0264ebd8 100644
--- a/net/dsa/tag_8021q.c
+++ b/net/dsa/tag_8021q.c
@@ -6,7 +6,6 @@
* dsa_8021q_netdev_ops is registered for API compliance and not used
* directly by callers.
*/
-#include <linux/if_bridge.h>
#include <linux/if_vlan.h>
#include <linux/dsa/8021q.h>
diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c
index fa1d60d13ad9..3509fc967ca9 100644
--- a/net/dsa/tag_ksz.c
+++ b/net/dsa/tag_ksz.c
@@ -6,7 +6,6 @@
#include <linux/etherdevice.h>
#include <linux/list.h>
-#include <linux/slab.h>
#include <net/dsa.h>
#include "dsa_priv.h"
diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c
index 605b51ca6921..cd60b94fc175 100644
--- a/net/dsa/tag_ocelot.c
+++ b/net/dsa/tag_ocelot.c
@@ -4,15 +4,52 @@
#include <linux/dsa/ocelot.h>
#include "dsa_priv.h"
+/* If the port is under a VLAN-aware bridge, remove the VLAN header from the
+ * payload and move it into the DSA tag, which will make the switch classify
+ * the packet to the bridge VLAN. Otherwise, leave the classified VLAN at zero,
+ * which is the pvid of standalone and VLAN-unaware bridge ports.
+ */
+static void ocelot_xmit_get_vlan_info(struct sk_buff *skb, struct dsa_port *dp,
+ u64 *vlan_tci, u64 *tag_type)
+{
+ struct net_device *br = READ_ONCE(dp->bridge_dev);
+ struct vlan_ethhdr *hdr;
+ u16 proto, tci;
+
+ if (!br || !br_vlan_enabled(br)) {
+ *vlan_tci = 0;
+ *tag_type = IFH_TAG_TYPE_C;
+ return;
+ }
+
+ hdr = (struct vlan_ethhdr *)skb_mac_header(skb);
+ br_vlan_get_proto(br, &proto);
+
+ if (ntohs(hdr->h_vlan_proto) == proto) {
+ __skb_vlan_pop(skb, &tci);
+ *vlan_tci = tci;
+ } else {
+ rcu_read_lock();
+ br_vlan_get_pvid_rcu(br, &tci);
+ rcu_read_unlock();
+ *vlan_tci = tci;
+ }
+
+ *tag_type = (proto != ETH_P_8021Q) ? IFH_TAG_TYPE_S : IFH_TAG_TYPE_C;
+}
+
static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
__be32 ifh_prefix, void **ifh)
{
struct dsa_port *dp = dsa_slave_to_port(netdev);
struct dsa_switch *ds = dp->ds;
+ u64 vlan_tci, tag_type;
void *injection;
__be32 *prefix;
u32 rew_op = 0;
+ ocelot_xmit_get_vlan_info(skb, dp, &vlan_tci, &tag_type);
+
injection = skb_push(skb, OCELOT_TAG_LEN);
prefix = skb_push(skb, OCELOT_SHORT_PREFIX_LEN);
@@ -21,6 +58,8 @@ static void ocelot_xmit_common(struct sk_buff *skb, struct net_device *netdev,
ocelot_ifh_set_bypass(injection, 1);
ocelot_ifh_set_src(injection, ds->num_ports);
ocelot_ifh_set_qos_class(injection, skb->priority);
+ ocelot_ifh_set_vlan_tci(injection, vlan_tci);
+ ocelot_ifh_set_tag_type(injection, tag_type);
rew_op = ocelot_ptp_rew_op(skb);
if (rew_op)
diff --git a/net/dsa/tag_rtl4_a.c b/net/dsa/tag_rtl4_a.c
index f920487ae145..6d928ee3ef7a 100644
--- a/net/dsa/tag_rtl4_a.c
+++ b/net/dsa/tag_rtl4_a.c
@@ -54,7 +54,7 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
p = (__be16 *)tag;
*p = htons(RTL4_A_ETHERTYPE);
- out = (RTL4_A_PROTOCOL_RTL8366RB << RTL4_A_PROTOCOL_SHIFT) | (2 << 8);
+ out = (RTL4_A_PROTOCOL_RTL8366RB << RTL4_A_PROTOCOL_SHIFT);
/* The lower bits indicate the port number */
out |= BIT(dp->index);