Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Just minor overlapping changes in the conflicts here. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -27,7 +27,6 @@
|
||||
#include <linux/platform_data/mv88e6xxx.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
@@ -430,7 +429,7 @@ int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link,
|
||||
return 0;
|
||||
|
||||
/* Port's MAC control must not be changed unless the link is down */
|
||||
err = chip->info->ops->port_set_link(chip, port, 0);
|
||||
err = chip->info->ops->port_set_link(chip, port, LINK_FORCED_DOWN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -482,30 +481,6 @@ static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port)
|
||||
return port < chip->info->num_internal_phys;
|
||||
}
|
||||
|
||||
/* We expect the switch to perform auto negotiation if there is a real
|
||||
* phy. However, in the case of a fixed link phy, we force the port
|
||||
* settings from the fixed link settings.
|
||||
*/
|
||||
static void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port,
|
||||
struct phy_device *phydev)
|
||||
{
|
||||
struct mv88e6xxx_chip *chip = ds->priv;
|
||||
int err;
|
||||
|
||||
if (!phy_is_pseudo_fixed_link(phydev) &&
|
||||
mv88e6xxx_phy_is_internal(ds, port))
|
||||
return;
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
err = mv88e6xxx_port_setup_mac(chip, port, phydev->link, phydev->speed,
|
||||
phydev->duplex, phydev->pause,
|
||||
phydev->interface);
|
||||
mv88e6xxx_reg_unlock(chip);
|
||||
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
dev_err(ds->dev, "p%d: failed to configure MAC\n", port);
|
||||
}
|
||||
|
||||
static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port,
|
||||
unsigned long *mask,
|
||||
struct phylink_link_state *state)
|
||||
@@ -2747,6 +2722,7 @@ static int mv88e6xxx_mdios_register(struct mv88e6xxx_chip *chip,
|
||||
err = mv88e6xxx_mdio_register(chip, child, true);
|
||||
if (err) {
|
||||
mv88e6xxx_mdios_unregister(chip);
|
||||
of_node_put(child);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@@ -4720,7 +4696,6 @@ static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port,
|
||||
static const struct dsa_switch_ops mv88e6xxx_switch_ops = {
|
||||
.get_tag_protocol = mv88e6xxx_get_tag_protocol,
|
||||
.setup = mv88e6xxx_setup,
|
||||
.adjust_link = mv88e6xxx_adjust_link,
|
||||
.phylink_validate = mv88e6xxx_validate,
|
||||
.phylink_mac_link_state = mv88e6xxx_link_state,
|
||||
.phylink_mac_config = mv88e6xxx_mac_config,
|
||||
|
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
|
||||
* Copyright (C) 2011-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2016 John Crispin <john@phrozen.org>
|
||||
*/
|
||||
|
||||
@@ -583,8 +583,11 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
|
||||
|
||||
for_each_available_child_of_node(ports, port) {
|
||||
err = of_property_read_u32(port, "reg", ®);
|
||||
if (err)
|
||||
if (err) {
|
||||
of_node_put(port);
|
||||
of_node_put(ports);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!dsa_is_user_port(priv->ds, reg))
|
||||
continue;
|
||||
@@ -595,6 +598,7 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
|
||||
internal_mdio_mask |= BIT(reg);
|
||||
}
|
||||
|
||||
of_node_put(ports);
|
||||
if (!external_mdio_mask && !internal_mdio_mask) {
|
||||
dev_err(priv->dev, "no PHYs are defined.\n");
|
||||
return -EINVAL;
|
||||
@@ -935,6 +939,8 @@ qca8k_port_enable(struct dsa_switch *ds, int port,
|
||||
qca8k_port_set_status(priv, port, 1);
|
||||
priv->port_sts[port].enabled = 1;
|
||||
|
||||
phy_support_asym_pause(phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -277,6 +277,18 @@ sja1105et_l2_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
|
||||
SJA1105ET_SIZE_L2_LOOKUP_ENTRY, op);
|
||||
}
|
||||
|
||||
static size_t sja1105et_dyn_l2_lookup_entry_packing(void *buf, void *entry_ptr,
|
||||
enum packing_op op)
|
||||
{
|
||||
struct sja1105_l2_lookup_entry *entry = entry_ptr;
|
||||
u8 *cmd = buf + SJA1105ET_SIZE_L2_LOOKUP_ENTRY;
|
||||
const int size = SJA1105_SIZE_DYN_CMD;
|
||||
|
||||
sja1105_packing(cmd, &entry->lockeds, 28, 28, size, op);
|
||||
|
||||
return sja1105et_l2_lookup_entry_packing(buf, entry_ptr, op);
|
||||
}
|
||||
|
||||
static void
|
||||
sja1105et_mgmt_route_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
|
||||
enum packing_op op)
|
||||
@@ -477,7 +489,7 @@ sja1105et_general_params_entry_packing(void *buf, void *entry_ptr,
|
||||
/* SJA1105E/T: First generation */
|
||||
struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
|
||||
[BLK_IDX_L2_LOOKUP] = {
|
||||
.entry_packing = sja1105et_l2_lookup_entry_packing,
|
||||
.entry_packing = sja1105et_dyn_l2_lookup_entry_packing,
|
||||
.cmd_packing = sja1105et_l2_lookup_cmd_packing,
|
||||
.access = (OP_READ | OP_WRITE | OP_DEL),
|
||||
.max_entry_count = SJA1105_MAX_L2_LOOKUP_COUNT,
|
||||
|
@@ -218,7 +218,7 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
|
||||
/* This selects between Independent VLAN Learning (IVL) and
|
||||
* Shared VLAN Learning (SVL)
|
||||
*/
|
||||
.shared_learn = false,
|
||||
.shared_learn = true,
|
||||
/* Don't discard management traffic based on ENFPORT -
|
||||
* we don't perform SMAC port enforcement anyway, so
|
||||
* what we are setting here doesn't matter.
|
||||
@@ -625,6 +625,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
|
||||
if (of_property_read_u32(child, "reg", &index) < 0) {
|
||||
dev_err(dev, "Port number not defined in device tree "
|
||||
"(property \"reg\")\n");
|
||||
of_node_put(child);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -634,6 +635,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
|
||||
dev_err(dev, "Failed to read phy-mode or "
|
||||
"phy-interface-type property for port %d\n",
|
||||
index);
|
||||
of_node_put(child);
|
||||
return -ENODEV;
|
||||
}
|
||||
ports[index].phy_mode = phy_mode;
|
||||
@@ -643,6 +645,7 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
|
||||
if (!of_phy_is_fixed_link(child)) {
|
||||
dev_err(dev, "phy-handle or fixed-link "
|
||||
"properties missing!\n");
|
||||
of_node_put(child);
|
||||
return -ENODEV;
|
||||
}
|
||||
/* phy-handle is missing, but fixed-link isn't.
|
||||
@@ -1089,8 +1092,13 @@ int sja1105pqrs_fdb_add(struct dsa_switch *ds, int port,
|
||||
l2_lookup.vlanid = vid;
|
||||
l2_lookup.iotag = SJA1105_S_TAG;
|
||||
l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0);
|
||||
l2_lookup.mask_vlanid = VLAN_VID_MASK;
|
||||
l2_lookup.mask_iotag = BIT(0);
|
||||
if (dsa_port_is_vlan_filtering(&ds->ports[port])) {
|
||||
l2_lookup.mask_vlanid = VLAN_VID_MASK;
|
||||
l2_lookup.mask_iotag = BIT(0);
|
||||
} else {
|
||||
l2_lookup.mask_vlanid = 0;
|
||||
l2_lookup.mask_iotag = 0;
|
||||
}
|
||||
l2_lookup.destports = BIT(port);
|
||||
|
||||
rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
|
||||
@@ -1147,8 +1155,13 @@ int sja1105pqrs_fdb_del(struct dsa_switch *ds, int port,
|
||||
l2_lookup.vlanid = vid;
|
||||
l2_lookup.iotag = SJA1105_S_TAG;
|
||||
l2_lookup.mask_macaddr = GENMASK_ULL(ETH_ALEN * 8 - 1, 0);
|
||||
l2_lookup.mask_vlanid = VLAN_VID_MASK;
|
||||
l2_lookup.mask_iotag = BIT(0);
|
||||
if (dsa_port_is_vlan_filtering(&ds->ports[port])) {
|
||||
l2_lookup.mask_vlanid = VLAN_VID_MASK;
|
||||
l2_lookup.mask_iotag = BIT(0);
|
||||
} else {
|
||||
l2_lookup.mask_vlanid = 0;
|
||||
l2_lookup.mask_iotag = 0;
|
||||
}
|
||||
l2_lookup.destports = BIT(port);
|
||||
|
||||
rc = sja1105_dynamic_config_read(priv, BLK_IDX_L2_LOOKUP,
|
||||
@@ -1178,60 +1191,31 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port,
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
struct sja1105_private *priv = ds->priv;
|
||||
u16 rx_vid, tx_vid;
|
||||
int rc, i;
|
||||
|
||||
if (dsa_port_is_vlan_filtering(&ds->ports[port]))
|
||||
return priv->info->fdb_add_cmd(ds, port, addr, vid);
|
||||
|
||||
/* Since we make use of VLANs even when the bridge core doesn't tell us
|
||||
* to, translate these FDB entries into the correct dsa_8021q ones.
|
||||
* The basic idea (also repeats for removal below) is:
|
||||
* - Each of the other front-panel ports needs to be able to forward a
|
||||
* pvid-tagged (aka tagged with their rx_vid) frame that matches this
|
||||
* DMAC.
|
||||
* - The CPU port (aka the tx_vid of this port) needs to be able to
|
||||
* send a frame matching this DMAC to the specified port.
|
||||
* For a better picture see net/dsa/tag_8021q.c.
|
||||
/* dsa_8021q is in effect when the bridge's vlan_filtering isn't,
|
||||
* so the switch still does some VLAN processing internally.
|
||||
* But Shared VLAN Learning (SVL) is also active, and it will take
|
||||
* care of autonomous forwarding between the unique pvid's of each
|
||||
* port. Here we just make sure that users can't add duplicate FDB
|
||||
* entries when in this mode - the actual VID doesn't matter except
|
||||
* for what gets printed in 'bridge fdb show'. In the case of zero,
|
||||
* no VID gets printed at all.
|
||||
*/
|
||||
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
|
||||
if (i == port)
|
||||
continue;
|
||||
if (i == dsa_upstream_port(priv->ds, port))
|
||||
continue;
|
||||
if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
|
||||
vid = 0;
|
||||
|
||||
rx_vid = dsa_8021q_rx_vid(ds, i);
|
||||
rc = priv->info->fdb_add_cmd(ds, port, addr, rx_vid);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
tx_vid = dsa_8021q_tx_vid(ds, port);
|
||||
return priv->info->fdb_add_cmd(ds, port, addr, tx_vid);
|
||||
return priv->info->fdb_add_cmd(ds, port, addr, vid);
|
||||
}
|
||||
|
||||
static int sja1105_fdb_del(struct dsa_switch *ds, int port,
|
||||
const unsigned char *addr, u16 vid)
|
||||
{
|
||||
struct sja1105_private *priv = ds->priv;
|
||||
u16 rx_vid, tx_vid;
|
||||
int rc, i;
|
||||
|
||||
if (dsa_port_is_vlan_filtering(&ds->ports[port]))
|
||||
return priv->info->fdb_del_cmd(ds, port, addr, vid);
|
||||
if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
|
||||
vid = 0;
|
||||
|
||||
for (i = 0; i < SJA1105_NUM_PORTS; i++) {
|
||||
if (i == port)
|
||||
continue;
|
||||
if (i == dsa_upstream_port(priv->ds, port))
|
||||
continue;
|
||||
|
||||
rx_vid = dsa_8021q_rx_vid(ds, i);
|
||||
rc = priv->info->fdb_del_cmd(ds, port, addr, rx_vid);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
tx_vid = dsa_8021q_tx_vid(ds, port);
|
||||
return priv->info->fdb_del_cmd(ds, port, addr, tx_vid);
|
||||
return priv->info->fdb_del_cmd(ds, port, addr, vid);
|
||||
}
|
||||
|
||||
static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
|
||||
@@ -1270,39 +1254,9 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port,
|
||||
continue;
|
||||
u64_to_ether_addr(l2_lookup.macaddr, macaddr);
|
||||
|
||||
/* On SJA1105 E/T, the switch doesn't implement the LOCKEDS
|
||||
* bit, so it doesn't tell us whether a FDB entry is static
|
||||
* or not.
|
||||
* But, of course, we can find out - we're the ones who added
|
||||
* it in the first place.
|
||||
*/
|
||||
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
|
||||
priv->info->device_id == SJA1105T_DEVICE_ID) {
|
||||
int match;
|
||||
|
||||
match = sja1105_find_static_fdb_entry(priv, port,
|
||||
&l2_lookup);
|
||||
l2_lookup.lockeds = (match >= 0);
|
||||
}
|
||||
|
||||
/* We need to hide the dsa_8021q VLANs from the user. This
|
||||
* basically means hiding the duplicates and only showing
|
||||
* the pvid that is supposed to be active in standalone and
|
||||
* non-vlan_filtering modes (aka 1).
|
||||
* - For statically added FDB entries (bridge fdb add), we
|
||||
* can convert the TX VID (coming from the CPU port) into the
|
||||
* pvid and ignore the RX VIDs of the other ports.
|
||||
* - For dynamically learned FDB entries, a single entry with
|
||||
* no duplicates is learned - that which has the real port's
|
||||
* pvid, aka RX VID.
|
||||
*/
|
||||
if (!dsa_port_is_vlan_filtering(&ds->ports[port])) {
|
||||
if (l2_lookup.vlanid == tx_vid ||
|
||||
l2_lookup.vlanid == rx_vid)
|
||||
l2_lookup.vlanid = 1;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
/* We need to hide the dsa_8021q VLANs from the user. */
|
||||
if (!dsa_port_is_vlan_filtering(&ds->ports[port]))
|
||||
l2_lookup.vlanid = 0;
|
||||
cb(macaddr, l2_lookup.vlanid, l2_lookup.lockeds, data);
|
||||
}
|
||||
return 0;
|
||||
@@ -1594,6 +1548,7 @@ static int sja1105_vlan_prepare(struct dsa_switch *ds, int port,
|
||||
*/
|
||||
static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
|
||||
{
|
||||
struct sja1105_l2_lookup_params_entry *l2_lookup_params;
|
||||
struct sja1105_general_params_entry *general_params;
|
||||
struct sja1105_private *priv = ds->priv;
|
||||
struct sja1105_table *table;
|
||||
@@ -1622,6 +1577,28 @@ static int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled)
|
||||
general_params->incl_srcpt1 = enabled;
|
||||
general_params->incl_srcpt0 = enabled;
|
||||
|
||||
/* VLAN filtering => independent VLAN learning.
|
||||
* No VLAN filtering => shared VLAN learning.
|
||||
*
|
||||
* In shared VLAN learning mode, untagged traffic still gets
|
||||
* pvid-tagged, and the FDB table gets populated with entries
|
||||
* containing the "real" (pvid or from VLAN tag) VLAN ID.
|
||||
* However the switch performs a masked L2 lookup in the FDB,
|
||||
* effectively only looking up a frame's DMAC (and not VID) for the
|
||||
* forwarding decision.
|
||||
*
|
||||
* This is extremely convenient for us, because in modes with
|
||||
* vlan_filtering=0, dsa_8021q actually installs unique pvid's into
|
||||
* each front panel port. This is good for identification but breaks
|
||||
* learning badly - the VID of the learnt FDB entry is unique, aka
|
||||
* no frames coming from any other port are going to have it. So
|
||||
* for forwarding purposes, this is as though learning was broken
|
||||
* (all frames get flooded).
|
||||
*/
|
||||
table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP_PARAMS];
|
||||
l2_lookup_params = table->entries;
|
||||
l2_lookup_params->shared_learn = !enabled;
|
||||
|
||||
rc = sja1105_static_config_reload(priv);
|
||||
if (rc)
|
||||
dev_err(ds->dev, "Failed to change VLAN Ethertype\n");
|
||||
@@ -1751,6 +1728,8 @@ static void sja1105_teardown(struct dsa_switch *ds)
|
||||
|
||||
cancel_work_sync(&priv->tagger_data.rxtstamp_work);
|
||||
skb_queue_purge(&priv->tagger_data.skb_rxtstamp_queue);
|
||||
sja1105_ptp_clock_unregister(priv);
|
||||
sja1105_static_config_free(&priv->static_config);
|
||||
}
|
||||
|
||||
static int sja1105_mgmt_xmit(struct dsa_switch *ds, int port, int slot,
|
||||
@@ -2208,9 +2187,7 @@ static int sja1105_remove(struct spi_device *spi)
|
||||
{
|
||||
struct sja1105_private *priv = spi_get_drvdata(spi);
|
||||
|
||||
sja1105_ptp_clock_unregister(priv);
|
||||
dsa_unregister_switch(priv->ds);
|
||||
sja1105_static_config_free(&priv->static_config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -369,16 +369,15 @@ int sja1105_ptp_clock_register(struct sja1105_private *priv)
|
||||
.mult = SJA1105_CC_MULT,
|
||||
};
|
||||
mutex_init(&priv->ptp_lock);
|
||||
INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check);
|
||||
|
||||
schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL);
|
||||
|
||||
priv->ptp_caps = sja1105_ptp_caps;
|
||||
|
||||
priv->clock = ptp_clock_register(&priv->ptp_caps, ds->dev);
|
||||
if (IS_ERR_OR_NULL(priv->clock))
|
||||
return PTR_ERR(priv->clock);
|
||||
|
||||
INIT_DELAYED_WORK(&priv->refresh_work, sja1105_ptp_overflow_check);
|
||||
schedule_delayed_work(&priv->refresh_work, SJA1105_REFRESH_INTERVAL);
|
||||
|
||||
return sja1105_ptp_reset(priv);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user