Merge branch 'sja1105-fixes'
Vladimir Oltean says: ==================== Fixes for SJA1105 DSA driver This series contains some minor fixes in the sja1105 driver: - improved error handling in the probe path - rejecting an invalid phy-mode specified in the device tree - register access fix for SJA1105P/Q/R/S for the virtual links through the dynamic reconfiguration interface - handling 2 bridge VLANs where the second is supposed to overwrite the first - making sure that the lack of a pvid results in the actual dropping of untagged traffic ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -167,9 +167,10 @@ enum sja1105_hostcmd {
|
|||||||
SJA1105_HOSTCMD_INVALIDATE = 4,
|
SJA1105_HOSTCMD_INVALIDATE = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Command and entry overlap */
|
||||||
static void
|
static void
|
||||||
sja1105_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
|
sja1105et_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
|
||||||
enum packing_op op)
|
enum packing_op op)
|
||||||
{
|
{
|
||||||
const int size = SJA1105_SIZE_DYN_CMD;
|
const int size = SJA1105_SIZE_DYN_CMD;
|
||||||
|
|
||||||
@@ -179,6 +180,20 @@ sja1105_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
|
|||||||
sja1105_packing(buf, &cmd->index, 9, 0, size, op);
|
sja1105_packing(buf, &cmd->index, 9, 0, size, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Command and entry are separate */
|
||||||
|
static void
|
||||||
|
sja1105pqrs_vl_lookup_cmd_packing(void *buf, struct sja1105_dyn_cmd *cmd,
|
||||||
|
enum packing_op op)
|
||||||
|
{
|
||||||
|
u8 *p = buf + SJA1105_SIZE_VL_LOOKUP_ENTRY;
|
||||||
|
const int size = SJA1105_SIZE_DYN_CMD;
|
||||||
|
|
||||||
|
sja1105_packing(p, &cmd->valid, 31, 31, size, op);
|
||||||
|
sja1105_packing(p, &cmd->errors, 30, 30, size, op);
|
||||||
|
sja1105_packing(p, &cmd->rdwrset, 29, 29, size, op);
|
||||||
|
sja1105_packing(p, &cmd->index, 9, 0, size, op);
|
||||||
|
}
|
||||||
|
|
||||||
static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
|
static size_t sja1105et_vl_lookup_entry_packing(void *buf, void *entry_ptr,
|
||||||
enum packing_op op)
|
enum packing_op op)
|
||||||
{
|
{
|
||||||
@@ -641,7 +656,7 @@ static size_t sja1105pqrs_cbs_entry_packing(void *buf, void *entry_ptr,
|
|||||||
const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
|
const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
|
||||||
[BLK_IDX_VL_LOOKUP] = {
|
[BLK_IDX_VL_LOOKUP] = {
|
||||||
.entry_packing = sja1105et_vl_lookup_entry_packing,
|
.entry_packing = sja1105et_vl_lookup_entry_packing,
|
||||||
.cmd_packing = sja1105_vl_lookup_cmd_packing,
|
.cmd_packing = sja1105et_vl_lookup_cmd_packing,
|
||||||
.access = OP_WRITE,
|
.access = OP_WRITE,
|
||||||
.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
|
.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
|
||||||
.packed_size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD,
|
.packed_size = SJA1105ET_SIZE_VL_LOOKUP_DYN_CMD,
|
||||||
@@ -725,7 +740,7 @@ const struct sja1105_dynamic_table_ops sja1105et_dyn_ops[BLK_IDX_MAX_DYN] = {
|
|||||||
const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
|
const struct sja1105_dynamic_table_ops sja1105pqrs_dyn_ops[BLK_IDX_MAX_DYN] = {
|
||||||
[BLK_IDX_VL_LOOKUP] = {
|
[BLK_IDX_VL_LOOKUP] = {
|
||||||
.entry_packing = sja1105_vl_lookup_entry_packing,
|
.entry_packing = sja1105_vl_lookup_entry_packing,
|
||||||
.cmd_packing = sja1105_vl_lookup_cmd_packing,
|
.cmd_packing = sja1105pqrs_vl_lookup_cmd_packing,
|
||||||
.access = (OP_READ | OP_WRITE),
|
.access = (OP_READ | OP_WRITE),
|
||||||
.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
|
.max_entry_count = SJA1105_MAX_VL_LOOKUP_COUNT,
|
||||||
.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
|
.packed_size = SJA1105PQRS_SIZE_VL_LOOKUP_DYN_CMD,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "sja1105_tas.h"
|
#include "sja1105_tas.h"
|
||||||
|
|
||||||
#define SJA1105_UNKNOWN_MULTICAST 0x010000000000ull
|
#define SJA1105_UNKNOWN_MULTICAST 0x010000000000ull
|
||||||
|
#define SJA1105_DEFAULT_VLAN (VLAN_N_VID - 1)
|
||||||
|
|
||||||
static const struct dsa_switch_ops sja1105_switch_ops;
|
static const struct dsa_switch_ops sja1105_switch_ops;
|
||||||
|
|
||||||
@@ -207,6 +208,7 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv,
|
|||||||
default:
|
default:
|
||||||
dev_err(dev, "Unsupported PHY mode %s!\n",
|
dev_err(dev, "Unsupported PHY mode %s!\n",
|
||||||
phy_modes(ports[i].phy_mode));
|
phy_modes(ports[i].phy_mode));
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Even though the SerDes port is able to drive SGMII autoneg
|
/* Even though the SerDes port is able to drive SGMII autoneg
|
||||||
@@ -321,6 +323,13 @@ static int sja1105_init_l2_lookup_params(struct sja1105_private *priv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set up a default VLAN for untagged traffic injected from the CPU
|
||||||
|
* using management routes (e.g. STP, PTP) as opposed to tag_8021q.
|
||||||
|
* All DT-defined ports are members of this VLAN, and there are no
|
||||||
|
* restrictions on forwarding (since the CPU selects the destination).
|
||||||
|
* Frames from this VLAN will always be transmitted as untagged, and
|
||||||
|
* neither the bridge nor the 8021q module cannot create this VLAN ID.
|
||||||
|
*/
|
||||||
static int sja1105_init_static_vlan(struct sja1105_private *priv)
|
static int sja1105_init_static_vlan(struct sja1105_private *priv)
|
||||||
{
|
{
|
||||||
struct sja1105_table *table;
|
struct sja1105_table *table;
|
||||||
@@ -330,17 +339,13 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
|
|||||||
.vmemb_port = 0,
|
.vmemb_port = 0,
|
||||||
.vlan_bc = 0,
|
.vlan_bc = 0,
|
||||||
.tag_port = 0,
|
.tag_port = 0,
|
||||||
.vlanid = 1,
|
.vlanid = SJA1105_DEFAULT_VLAN,
|
||||||
};
|
};
|
||||||
struct dsa_switch *ds = priv->ds;
|
struct dsa_switch *ds = priv->ds;
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
table = &priv->static_config.tables[BLK_IDX_VLAN_LOOKUP];
|
table = &priv->static_config.tables[BLK_IDX_VLAN_LOOKUP];
|
||||||
|
|
||||||
/* The static VLAN table will only contain the initial pvid of 1.
|
|
||||||
* All other VLANs are to be configured through dynamic entries,
|
|
||||||
* and kept in the static configuration table as backing memory.
|
|
||||||
*/
|
|
||||||
if (table->entry_count) {
|
if (table->entry_count) {
|
||||||
kfree(table->entries);
|
kfree(table->entries);
|
||||||
table->entry_count = 0;
|
table->entry_count = 0;
|
||||||
@@ -353,9 +358,6 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
|
|||||||
|
|
||||||
table->entry_count = 1;
|
table->entry_count = 1;
|
||||||
|
|
||||||
/* VLAN 1: all DT-defined ports are members; no restrictions on
|
|
||||||
* forwarding; always transmit as untagged.
|
|
||||||
*/
|
|
||||||
for (port = 0; port < ds->num_ports; port++) {
|
for (port = 0; port < ds->num_ports; port++) {
|
||||||
struct sja1105_bridge_vlan *v;
|
struct sja1105_bridge_vlan *v;
|
||||||
|
|
||||||
@@ -366,15 +368,12 @@ static int sja1105_init_static_vlan(struct sja1105_private *priv)
|
|||||||
pvid.vlan_bc |= BIT(port);
|
pvid.vlan_bc |= BIT(port);
|
||||||
pvid.tag_port &= ~BIT(port);
|
pvid.tag_port &= ~BIT(port);
|
||||||
|
|
||||||
/* Let traffic that don't need dsa_8021q (e.g. STP, PTP) be
|
|
||||||
* transmitted as untagged.
|
|
||||||
*/
|
|
||||||
v = kzalloc(sizeof(*v), GFP_KERNEL);
|
v = kzalloc(sizeof(*v), GFP_KERNEL);
|
||||||
if (!v)
|
if (!v)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
v->port = port;
|
v->port = port;
|
||||||
v->vid = 1;
|
v->vid = SJA1105_DEFAULT_VLAN;
|
||||||
v->untagged = true;
|
v->untagged = true;
|
||||||
if (dsa_is_cpu_port(ds, port))
|
if (dsa_is_cpu_port(ds, port))
|
||||||
v->pvid = true;
|
v->pvid = true;
|
||||||
@@ -2817,11 +2816,22 @@ static int sja1105_vlan_add_one(struct dsa_switch *ds, int port, u16 vid,
|
|||||||
bool pvid = flags & BRIDGE_VLAN_INFO_PVID;
|
bool pvid = flags & BRIDGE_VLAN_INFO_PVID;
|
||||||
struct sja1105_bridge_vlan *v;
|
struct sja1105_bridge_vlan *v;
|
||||||
|
|
||||||
list_for_each_entry(v, vlan_list, list)
|
list_for_each_entry(v, vlan_list, list) {
|
||||||
if (v->port == port && v->vid == vid &&
|
if (v->port == port && v->vid == vid) {
|
||||||
v->untagged == untagged && v->pvid == pvid)
|
|
||||||
/* Already added */
|
/* Already added */
|
||||||
return 0;
|
if (v->untagged == untagged && v->pvid == pvid)
|
||||||
|
/* Nothing changed */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* It's the same VLAN, but some of the flags changed
|
||||||
|
* and the user did not bother to delete it first.
|
||||||
|
* Update it and trigger sja1105_build_vlan_table.
|
||||||
|
*/
|
||||||
|
v->untagged = untagged;
|
||||||
|
v->pvid = pvid;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
v = kzalloc(sizeof(*v), GFP_KERNEL);
|
v = kzalloc(sizeof(*v), GFP_KERNEL);
|
||||||
if (!v) {
|
if (!v) {
|
||||||
@@ -2976,13 +2986,13 @@ static int sja1105_setup(struct dsa_switch *ds)
|
|||||||
rc = sja1105_static_config_load(priv, ports);
|
rc = sja1105_static_config_load(priv, ports);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
dev_err(ds->dev, "Failed to load static config: %d\n", rc);
|
dev_err(ds->dev, "Failed to load static config: %d\n", rc);
|
||||||
return rc;
|
goto out_ptp_clock_unregister;
|
||||||
}
|
}
|
||||||
/* Configure the CGU (PHY link modes and speeds) */
|
/* Configure the CGU (PHY link modes and speeds) */
|
||||||
rc = sja1105_clocking_setup(priv);
|
rc = sja1105_clocking_setup(priv);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
dev_err(ds->dev, "Failed to configure MII clocking: %d\n", rc);
|
dev_err(ds->dev, "Failed to configure MII clocking: %d\n", rc);
|
||||||
return rc;
|
goto out_static_config_free;
|
||||||
}
|
}
|
||||||
/* On SJA1105, VLAN filtering per se is always enabled in hardware.
|
/* On SJA1105, VLAN filtering per se is always enabled in hardware.
|
||||||
* The only thing we can do to disable it is lie about what the 802.1Q
|
* The only thing we can do to disable it is lie about what the 802.1Q
|
||||||
@@ -3003,7 +3013,7 @@ static int sja1105_setup(struct dsa_switch *ds)
|
|||||||
|
|
||||||
rc = sja1105_devlink_setup(ds);
|
rc = sja1105_devlink_setup(ds);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
goto out_static_config_free;
|
||||||
|
|
||||||
/* The DSA/switchdev model brings up switch ports in standalone mode by
|
/* The DSA/switchdev model brings up switch ports in standalone mode by
|
||||||
* default, and that means vlan_filtering is 0 since they're not under
|
* default, and that means vlan_filtering is 0 since they're not under
|
||||||
@@ -3012,6 +3022,17 @@ static int sja1105_setup(struct dsa_switch *ds)
|
|||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
rc = sja1105_setup_8021q_tagging(ds, true);
|
rc = sja1105_setup_8021q_tagging(ds, true);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
if (rc)
|
||||||
|
goto out_devlink_teardown;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_devlink_teardown:
|
||||||
|
sja1105_devlink_teardown(ds);
|
||||||
|
out_ptp_clock_unregister:
|
||||||
|
sja1105_ptp_clock_unregister(ds);
|
||||||
|
out_static_config_free:
|
||||||
|
sja1105_static_config_free(&priv->static_config);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -3646,8 +3667,10 @@ static int sja1105_probe(struct spi_device *spi)
|
|||||||
priv->cbs = devm_kcalloc(dev, priv->info->num_cbs_shapers,
|
priv->cbs = devm_kcalloc(dev, priv->info->num_cbs_shapers,
|
||||||
sizeof(struct sja1105_cbs_entry),
|
sizeof(struct sja1105_cbs_entry),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!priv->cbs)
|
if (!priv->cbs) {
|
||||||
return -ENOMEM;
|
rc = -ENOMEM;
|
||||||
|
goto out_unregister_switch;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connections between dsa_port and sja1105_port */
|
/* Connections between dsa_port and sja1105_port */
|
||||||
@@ -3672,7 +3695,7 @@ static int sja1105_probe(struct spi_device *spi)
|
|||||||
dev_err(ds->dev,
|
dev_err(ds->dev,
|
||||||
"failed to create deferred xmit thread: %d\n",
|
"failed to create deferred xmit thread: %d\n",
|
||||||
rc);
|
rc);
|
||||||
goto out;
|
goto out_destroy_workers;
|
||||||
}
|
}
|
||||||
skb_queue_head_init(&sp->xmit_queue);
|
skb_queue_head_init(&sp->xmit_queue);
|
||||||
sp->xmit_tpid = ETH_P_SJA1105;
|
sp->xmit_tpid = ETH_P_SJA1105;
|
||||||
@@ -3682,7 +3705,8 @@ static int sja1105_probe(struct spi_device *spi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out:
|
|
||||||
|
out_destroy_workers:
|
||||||
while (port-- > 0) {
|
while (port-- > 0) {
|
||||||
struct sja1105_port *sp = &priv->ports[port];
|
struct sja1105_port *sp = &priv->ports[port];
|
||||||
|
|
||||||
@@ -3691,6 +3715,10 @@ out:
|
|||||||
|
|
||||||
kthread_destroy_worker(sp->xmit_worker);
|
kthread_destroy_worker(sp->xmit_worker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out_unregister_switch:
|
||||||
|
dsa_unregister_switch(ds);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user