Commit 593c9c7c authored by Razvan Stefanescu's avatar Razvan Stefanescu Committed by Greg Kroah-Hartman

staging: fsl-dpaa2/ethsw: Fix tag control information value overwrite

The tag control information (TCI) part of the VLAN header contains several
fields, including PCP (priority code point) and PVID (port VLAN id).

Current implementation uses function ethsw_port_set_tci() to set the PVID
value and mistakenly overwrites the rest of the TCI fields with 0,
including PCP which by default has a value of 7.

Fix this by adding support to retrieve TCI set in hardware. Read existing
value and only updated the PVID fields, leaving others unchanged.
Signed-off-by: default avatarRazvan Stefanescu <razvan.stefanescu@nxp.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1494cb32
...@@ -49,6 +49,8 @@ ...@@ -49,6 +49,8 @@
#define DPSW_CMDID_IF_SET_FLOODING DPSW_CMD_ID(0x047) #define DPSW_CMDID_IF_SET_FLOODING DPSW_CMD_ID(0x047)
#define DPSW_CMDID_IF_SET_BROADCAST DPSW_CMD_ID(0x048) #define DPSW_CMDID_IF_SET_BROADCAST DPSW_CMD_ID(0x048)
#define DPSW_CMDID_IF_GET_TCI DPSW_CMD_ID(0x04A)
#define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C) #define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C)
#define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060) #define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060)
...@@ -206,6 +208,17 @@ struct dpsw_cmd_if_set_tci { ...@@ -206,6 +208,17 @@ struct dpsw_cmd_if_set_tci {
__le16 conf; __le16 conf;
}; };
struct dpsw_cmd_if_get_tci {
__le16 if_id;
};
struct dpsw_rsp_if_get_tci {
__le16 pad;
__le16 vlan_id;
u8 dei;
u8 pcp;
};
#define DPSW_STATE_SHIFT 0 #define DPSW_STATE_SHIFT 0
#define DPSW_STATE_SIZE 4 #define DPSW_STATE_SIZE 4
......
...@@ -528,6 +528,48 @@ int dpsw_if_set_tci(struct fsl_mc_io *mc_io, ...@@ -528,6 +528,48 @@ int dpsw_if_set_tci(struct fsl_mc_io *mc_io,
return mc_send_command(mc_io, &cmd); return mc_send_command(mc_io, &cmd);
} }
/**
* dpsw_if_get_tci() - Get default VLAN Tag Control Information (TCI)
* @mc_io: Pointer to MC portal's I/O object
* @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
* @token: Token of DPSW object
* @if_id: Interface Identifier
* @cfg: Tag Control Information Configuration
*
* Return: Completion status. '0' on Success; Error code otherwise.
*/
int dpsw_if_get_tci(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token,
u16 if_id,
struct dpsw_tci_cfg *cfg)
{
struct fsl_mc_command cmd = { 0 };
struct dpsw_cmd_if_get_tci *cmd_params;
struct dpsw_rsp_if_get_tci *rsp_params;
int err;
/* prepare command */
cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_TCI,
cmd_flags,
token);
cmd_params = (struct dpsw_cmd_if_get_tci *)cmd.params;
cmd_params->if_id = cpu_to_le16(if_id);
/* send command to mc*/
err = mc_send_command(mc_io, &cmd);
if (err)
return err;
/* retrieve response parameters */
rsp_params = (struct dpsw_rsp_if_get_tci *)cmd.params;
cfg->pcp = rsp_params->pcp;
cfg->dei = rsp_params->dei;
cfg->vlan_id = le16_to_cpu(rsp_params->vlan_id);
return 0;
}
/** /**
* dpsw_if_set_stp() - Function sets Spanning Tree Protocol (STP) state. * dpsw_if_set_stp() - Function sets Spanning Tree Protocol (STP) state.
* @mc_io: Pointer to MC portal's I/O object * @mc_io: Pointer to MC portal's I/O object
......
...@@ -306,6 +306,12 @@ int dpsw_if_set_tci(struct fsl_mc_io *mc_io, ...@@ -306,6 +306,12 @@ int dpsw_if_set_tci(struct fsl_mc_io *mc_io,
u16 if_id, u16 if_id,
const struct dpsw_tci_cfg *cfg); const struct dpsw_tci_cfg *cfg);
int dpsw_if_get_tci(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token,
u16 if_id,
struct dpsw_tci_cfg *cfg);
/** /**
* enum dpsw_stp_state - Spanning Tree Protocol (STP) states * enum dpsw_stp_state - Spanning Tree Protocol (STP) states
* @DPSW_STP_STATE_BLOCKING: Blocking state * @DPSW_STP_STATE_BLOCKING: Blocking state
......
...@@ -50,14 +50,23 @@ static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid) ...@@ -50,14 +50,23 @@ static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid)
return 0; return 0;
} }
static int ethsw_port_set_tci(struct ethsw_port_priv *port_priv, static int ethsw_port_set_pvid(struct ethsw_port_priv *port_priv, u16 pvid)
struct dpsw_tci_cfg *tci_cfg)
{ {
struct ethsw_core *ethsw = port_priv->ethsw_data; struct ethsw_core *ethsw = port_priv->ethsw_data;
struct net_device *netdev = port_priv->netdev; struct net_device *netdev = port_priv->netdev;
struct dpsw_tci_cfg tci_cfg = { 0 };
bool is_oper; bool is_oper;
int err, ret; int err, ret;
err = dpsw_if_get_tci(ethsw->mc_io, 0, ethsw->dpsw_handle,
port_priv->idx, &tci_cfg);
if (err) {
netdev_err(netdev, "dpsw_if_get_tci err %d\n", err);
return err;
}
tci_cfg.vlan_id = pvid;
/* Interface needs to be down to change PVID */ /* Interface needs to be down to change PVID */
is_oper = netif_oper_up(netdev); is_oper = netif_oper_up(netdev);
if (is_oper) { if (is_oper) {
...@@ -71,17 +80,16 @@ static int ethsw_port_set_tci(struct ethsw_port_priv *port_priv, ...@@ -71,17 +80,16 @@ static int ethsw_port_set_tci(struct ethsw_port_priv *port_priv,
} }
err = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, err = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle,
port_priv->idx, tci_cfg); port_priv->idx, &tci_cfg);
if (err) { if (err) {
netdev_err(netdev, "dpsw_if_set_tci err %d\n", err); netdev_err(netdev, "dpsw_if_set_tci err %d\n", err);
goto set_tci_error; goto set_tci_error;
} }
/* Delete previous PVID info and mark the new one */ /* Delete previous PVID info and mark the new one */
if (port_priv->pvid) port_priv->vlans[port_priv->pvid] &= ~ETHSW_VLAN_PVID;
port_priv->vlans[port_priv->pvid] &= ~ETHSW_VLAN_PVID; port_priv->vlans[pvid] |= ETHSW_VLAN_PVID;
port_priv->vlans[tci_cfg->vlan_id] |= ETHSW_VLAN_PVID; port_priv->pvid = pvid;
port_priv->pvid = tci_cfg->vlan_id;
set_tci_error: set_tci_error:
if (is_oper) { if (is_oper) {
...@@ -133,13 +141,7 @@ static int ethsw_port_add_vlan(struct ethsw_port_priv *port_priv, ...@@ -133,13 +141,7 @@ static int ethsw_port_add_vlan(struct ethsw_port_priv *port_priv,
} }
if (flags & BRIDGE_VLAN_INFO_PVID) { if (flags & BRIDGE_VLAN_INFO_PVID) {
struct dpsw_tci_cfg tci_cfg = { err = ethsw_port_set_pvid(port_priv, vid);
.pcp = 0,
.dei = 0,
.vlan_id = vid,
};
err = ethsw_port_set_tci(port_priv, &tci_cfg);
if (err) if (err)
return err; return err;
} }
...@@ -817,9 +819,7 @@ static int ethsw_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid) ...@@ -817,9 +819,7 @@ static int ethsw_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid)
return -ENOENT; return -ENOENT;
if (port_priv->vlans[vid] & ETHSW_VLAN_PVID) { if (port_priv->vlans[vid] & ETHSW_VLAN_PVID) {
struct dpsw_tci_cfg tci_cfg = { 0 }; err = ethsw_port_set_pvid(port_priv, 0);
err = ethsw_port_set_tci(port_priv, &tci_cfg);
if (err) if (err)
return err; return err;
} }
...@@ -1252,7 +1252,6 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port) ...@@ -1252,7 +1252,6 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
const char def_mcast[ETH_ALEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01}; const char def_mcast[ETH_ALEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01};
struct net_device *netdev = port_priv->netdev; struct net_device *netdev = port_priv->netdev;
struct ethsw_core *ethsw = port_priv->ethsw_data; struct ethsw_core *ethsw = port_priv->ethsw_data;
struct dpsw_tci_cfg tci_cfg = {0};
struct dpsw_vlan_if_cfg vcfg; struct dpsw_vlan_if_cfg vcfg;
int err; int err;
...@@ -1270,7 +1269,7 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port) ...@@ -1270,7 +1269,7 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port)
return err; return err;
} }
err = ethsw_port_set_tci(port_priv, &tci_cfg); err = ethsw_port_set_pvid(port_priv, 0);
if (err) if (err)
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment