net: dsa: lantiq_gswip: serialize access to the PCE table
Looking at the code, the GSWIP switch appears to hold bridging service structures (VLANs, FDBs, forwarding rules) in PCE table entries. Hardware access to the PCE table is non-atomic, and is comprised of several register reads and writes. These accesses are currently serialized by the rtnl_lock, but DSA is changing its driver API and that lock will no longer be held when calling ->port_fdb_add() and ->port_fdb_del(). So this driver needs to serialize the access to the PCE table using its own locking scheme. This patch adds that. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Acked-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f239934cff
commit
49753a75b9
|
@ -276,6 +276,7 @@ struct gswip_priv {
|
|||
int num_gphy_fw;
|
||||
struct gswip_gphy_fw *gphy_fw;
|
||||
u32 port_vlan_filter;
|
||||
struct mutex pce_table_lock;
|
||||
};
|
||||
|
||||
struct gswip_pce_table_entry {
|
||||
|
@ -523,10 +524,14 @@ static int gswip_pce_table_entry_read(struct gswip_priv *priv,
|
|||
u16 addr_mode = tbl->key_mode ? GSWIP_PCE_TBL_CTRL_OPMOD_KSRD :
|
||||
GSWIP_PCE_TBL_CTRL_OPMOD_ADRD;
|
||||
|
||||
mutex_lock(&priv->pce_table_lock);
|
||||
|
||||
err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
|
||||
GSWIP_PCE_TBL_CTRL_BAS);
|
||||
if (err)
|
||||
if (err) {
|
||||
mutex_unlock(&priv->pce_table_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
gswip_switch_w(priv, tbl->index, GSWIP_PCE_TBL_ADDR);
|
||||
gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK |
|
||||
|
@ -536,8 +541,10 @@ static int gswip_pce_table_entry_read(struct gswip_priv *priv,
|
|||
|
||||
err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
|
||||
GSWIP_PCE_TBL_CTRL_BAS);
|
||||
if (err)
|
||||
if (err) {
|
||||
mutex_unlock(&priv->pce_table_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tbl->key); i++)
|
||||
tbl->key[i] = gswip_switch_r(priv, GSWIP_PCE_TBL_KEY(i));
|
||||
|
@ -553,6 +560,8 @@ static int gswip_pce_table_entry_read(struct gswip_priv *priv,
|
|||
tbl->valid = !!(crtl & GSWIP_PCE_TBL_CTRL_VLD);
|
||||
tbl->gmap = (crtl & GSWIP_PCE_TBL_CTRL_GMAP_MASK) >> 7;
|
||||
|
||||
mutex_unlock(&priv->pce_table_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -565,10 +574,14 @@ static int gswip_pce_table_entry_write(struct gswip_priv *priv,
|
|||
u16 addr_mode = tbl->key_mode ? GSWIP_PCE_TBL_CTRL_OPMOD_KSWR :
|
||||
GSWIP_PCE_TBL_CTRL_OPMOD_ADWR;
|
||||
|
||||
mutex_lock(&priv->pce_table_lock);
|
||||
|
||||
err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
|
||||
GSWIP_PCE_TBL_CTRL_BAS);
|
||||
if (err)
|
||||
if (err) {
|
||||
mutex_unlock(&priv->pce_table_lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
gswip_switch_w(priv, tbl->index, GSWIP_PCE_TBL_ADDR);
|
||||
gswip_switch_mask(priv, GSWIP_PCE_TBL_CTRL_ADDR_MASK |
|
||||
|
@ -600,8 +613,12 @@ static int gswip_pce_table_entry_write(struct gswip_priv *priv,
|
|||
crtl |= GSWIP_PCE_TBL_CTRL_BAS;
|
||||
gswip_switch_w(priv, crtl, GSWIP_PCE_TBL_CTRL);
|
||||
|
||||
return gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
|
||||
GSWIP_PCE_TBL_CTRL_BAS);
|
||||
err = gswip_switch_r_timeout(priv, GSWIP_PCE_TBL_CTRL,
|
||||
GSWIP_PCE_TBL_CTRL_BAS);
|
||||
|
||||
mutex_unlock(&priv->pce_table_lock);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Add the LAN port into a bridge with the CPU port by
|
||||
|
@ -2106,6 +2123,7 @@ static int gswip_probe(struct platform_device *pdev)
|
|||
priv->ds->priv = priv;
|
||||
priv->ds->ops = priv->hw_info->ops;
|
||||
priv->dev = dev;
|
||||
mutex_init(&priv->pce_table_lock);
|
||||
version = gswip_switch_r(priv, GSWIP_VERSION);
|
||||
|
||||
np = dev->of_node;
|
||||
|
|
Loading…
Reference in New Issue