Commit 0ca99c84 authored by David S. Miller's avatar David S. Miller

Merge branch 'dpaa2-switch-offload-port-flags'

Ioana Ciornei says:

====================
dpaa2-switch: offload bridge port flags to device

Add support for offloading bridge port flags to the switch. With this
patch set, the learning, broadcast flooding and unknown ucast/mcast
flooding states will be user configurable.

Apart from that, the last patch is a small fix that configures the
offload_fwd_mark if the switch port is under a bridge or not.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3adffc76 b175dfd7
...@@ -110,6 +110,63 @@ static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv, ...@@ -110,6 +110,63 @@ static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
return 0; return 0;
} }
static void dpaa2_switch_fdb_get_flood_cfg(struct ethsw_core *ethsw, u16 fdb_id,
enum dpsw_flood_type type,
struct dpsw_egress_flood_cfg *cfg)
{
int i = 0, j;
memset(cfg, 0, sizeof(*cfg));
/* Add all the DPAA2 switch ports found in the same bridging domain to
* the egress flooding domain
*/
for (j = 0; j < ethsw->sw_attr.num_ifs; j++) {
if (!ethsw->ports[j])
continue;
if (ethsw->ports[j]->fdb->fdb_id != fdb_id)
continue;
if (type == DPSW_BROADCAST && ethsw->ports[j]->bcast_flood)
cfg->if_id[i++] = ethsw->ports[j]->idx;
else if (type == DPSW_FLOODING && ethsw->ports[j]->ucast_flood)
cfg->if_id[i++] = ethsw->ports[j]->idx;
}
/* Add the CTRL interface to the egress flooding domain */
cfg->if_id[i++] = ethsw->sw_attr.num_ifs;
cfg->fdb_id = fdb_id;
cfg->flood_type = type;
cfg->num_ifs = i;
}
static int dpaa2_switch_fdb_set_egress_flood(struct ethsw_core *ethsw, u16 fdb_id)
{
struct dpsw_egress_flood_cfg flood_cfg;
int err;
/* Setup broadcast flooding domain */
dpaa2_switch_fdb_get_flood_cfg(ethsw, fdb_id, DPSW_BROADCAST, &flood_cfg);
err = dpsw_set_egress_flood(ethsw->mc_io, 0, ethsw->dpsw_handle,
&flood_cfg);
if (err) {
dev_err(ethsw->dev, "dpsw_set_egress_flood() = %d\n", err);
return err;
}
/* Setup unknown flooding domain */
dpaa2_switch_fdb_get_flood_cfg(ethsw, fdb_id, DPSW_FLOODING, &flood_cfg);
err = dpsw_set_egress_flood(ethsw->mc_io, 0, ethsw->dpsw_handle,
&flood_cfg);
if (err) {
dev_err(ethsw->dev, "dpsw_set_egress_flood() = %d\n", err);
return err;
}
return 0;
}
static void *dpaa2_iova_to_virt(struct iommu_domain *domain, static void *dpaa2_iova_to_virt(struct iommu_domain *domain,
dma_addr_t iova_addr) dma_addr_t iova_addr)
{ {
...@@ -1184,6 +1241,88 @@ static int dpaa2_switch_port_attr_stp_state_set(struct net_device *netdev, ...@@ -1184,6 +1241,88 @@ static int dpaa2_switch_port_attr_stp_state_set(struct net_device *netdev,
return dpaa2_switch_port_set_stp_state(port_priv, state); return dpaa2_switch_port_set_stp_state(port_priv, state);
} }
static int dpaa2_switch_port_set_learning(struct ethsw_port_priv *port_priv, bool enable)
{
struct ethsw_core *ethsw = port_priv->ethsw_data;
enum dpsw_learning_mode learn_mode;
int err;
if (enable)
learn_mode = DPSW_LEARNING_MODE_HW;
else
learn_mode = DPSW_LEARNING_MODE_DIS;
err = dpsw_if_set_learning_mode(ethsw->mc_io, 0, ethsw->dpsw_handle,
port_priv->idx, learn_mode);
if (err)
netdev_err(port_priv->netdev, "dpsw_if_set_learning_mode err %d\n", err);
if (!enable)
dpaa2_switch_port_fast_age(port_priv);
return err;
}
static int dpaa2_switch_port_flood(struct ethsw_port_priv *port_priv,
struct switchdev_brport_flags flags)
{
struct ethsw_core *ethsw = port_priv->ethsw_data;
if (flags.mask & BR_BCAST_FLOOD)
port_priv->bcast_flood = !!(flags.val & BR_BCAST_FLOOD);
if (flags.mask & BR_FLOOD)
port_priv->ucast_flood = !!(flags.val & BR_FLOOD);
return dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id);
}
static int dpaa2_switch_port_pre_bridge_flags(struct net_device *netdev,
struct switchdev_brport_flags flags,
struct netlink_ext_ack *extack)
{
if (flags.mask & ~(BR_LEARNING | BR_BCAST_FLOOD | BR_FLOOD |
BR_MCAST_FLOOD))
return -EINVAL;
if (flags.mask & (BR_FLOOD | BR_MCAST_FLOOD)) {
bool multicast = !!(flags.val & BR_MCAST_FLOOD);
bool unicast = !!(flags.val & BR_FLOOD);
if (unicast != multicast) {
NL_SET_ERR_MSG_MOD(extack,
"Cannot configure multicast flooding independently of unicast");
return -EINVAL;
}
}
return 0;
}
static int dpaa2_switch_port_bridge_flags(struct net_device *netdev,
struct switchdev_brport_flags flags,
struct netlink_ext_ack *extack)
{
struct ethsw_port_priv *port_priv = netdev_priv(netdev);
int err;
if (flags.mask & BR_LEARNING) {
bool learn_ena = !!(flags.val & BR_LEARNING);
err = dpaa2_switch_port_set_learning(port_priv, learn_ena);
if (err)
return err;
}
if (flags.mask & (BR_BCAST_FLOOD | BR_FLOOD | BR_MCAST_FLOOD)) {
err = dpaa2_switch_port_flood(port_priv, flags);
if (err)
return err;
}
return 0;
}
static int dpaa2_switch_port_attr_set(struct net_device *netdev, static int dpaa2_switch_port_attr_set(struct net_device *netdev,
const struct switchdev_attr *attr, const struct switchdev_attr *attr,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
...@@ -1202,6 +1341,12 @@ static int dpaa2_switch_port_attr_set(struct net_device *netdev, ...@@ -1202,6 +1341,12 @@ static int dpaa2_switch_port_attr_set(struct net_device *netdev,
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
break; break;
case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS:
err = dpaa2_switch_port_pre_bridge_flags(netdev, attr->u.brport_flags, extack);
break;
case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS:
err = dpaa2_switch_port_bridge_flags(netdev, attr->u.brport_flags, extack);
break;
default: default:
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
break; break;
...@@ -1442,48 +1587,6 @@ static int dpaa2_switch_port_attr_set_event(struct net_device *netdev, ...@@ -1442,48 +1587,6 @@ static int dpaa2_switch_port_attr_set_event(struct net_device *netdev,
return notifier_from_errno(err); return notifier_from_errno(err);
} }
static int dpaa2_switch_fdb_set_egress_flood(struct ethsw_core *ethsw, u16 fdb_id)
{
struct dpsw_egress_flood_cfg flood_cfg;
int i = 0, j;
int err;
/* Add all the DPAA2 switch ports found in the same bridging domain to
* the egress flooding domain
*/
for (j = 0; j < ethsw->sw_attr.num_ifs; j++)
if (ethsw->ports[j] && ethsw->ports[j]->fdb->fdb_id == fdb_id)
flood_cfg.if_id[i++] = ethsw->ports[j]->idx;
/* Add the CTRL interface to the egress flooding domain */
flood_cfg.if_id[i++] = ethsw->sw_attr.num_ifs;
/* Use the FDB of the first dpaa2 switch port added to the bridge */
flood_cfg.fdb_id = fdb_id;
/* Setup broadcast flooding domain */
flood_cfg.flood_type = DPSW_BROADCAST;
flood_cfg.num_ifs = i;
err = dpsw_set_egress_flood(ethsw->mc_io, 0, ethsw->dpsw_handle,
&flood_cfg);
if (err) {
dev_err(ethsw->dev, "dpsw_set_egress_flood() = %d\n", err);
return err;
}
/* Setup unknown flooding domain */
flood_cfg.flood_type = DPSW_FLOODING;
flood_cfg.num_ifs = i;
err = dpsw_set_egress_flood(ethsw->mc_io, 0, ethsw->dpsw_handle,
&flood_cfg);
if (err) {
dev_err(ethsw->dev, "dpsw_set_egress_flood() = %d\n", err);
return err;
}
return 0;
}
static int dpaa2_switch_port_bridge_join(struct net_device *netdev, static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
struct net_device *upper_dev) struct net_device *upper_dev)
{ {
...@@ -1492,6 +1595,7 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev, ...@@ -1492,6 +1595,7 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
struct ethsw_port_priv *other_port_priv; struct ethsw_port_priv *other_port_priv;
struct net_device *other_dev; struct net_device *other_dev;
struct list_head *iter; struct list_head *iter;
bool learn_ena;
int err; int err;
netdev_for_each_lower_dev(upper_dev, other_dev, iter) { netdev_for_each_lower_dev(upper_dev, other_dev, iter) {
...@@ -1513,6 +1617,10 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev, ...@@ -1513,6 +1617,10 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
dpaa2_switch_port_set_fdb(port_priv, upper_dev); dpaa2_switch_port_set_fdb(port_priv, upper_dev);
/* Inherit the initial bridge port learning state */
learn_ena = br_port_flag_is_set(netdev, BR_LEARNING);
err = dpaa2_switch_port_set_learning(port_priv, learn_ena);
/* Setup the egress flood policy (broadcast, unknown unicast) */ /* Setup the egress flood policy (broadcast, unknown unicast) */
err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id); err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id);
if (err) if (err)
...@@ -1570,6 +1678,13 @@ static int dpaa2_switch_port_bridge_leave(struct net_device *netdev) ...@@ -1570,6 +1678,13 @@ static int dpaa2_switch_port_bridge_leave(struct net_device *netdev)
if (err) if (err)
netdev_err(netdev, "Unable to restore RX VLANs to the new FDB, err (%d)\n", err); netdev_err(netdev, "Unable to restore RX VLANs to the new FDB, err (%d)\n", err);
/* Reset the flooding state to denote that this port can send any
* packet in standalone mode. With this, we are also ensuring that any
* later bridge join will have the flooding flag on.
*/
port_priv->bcast_flood = true;
port_priv->ucast_flood = true;
/* Setup the egress flood policy (broadcast, unknown unicast). /* Setup the egress flood policy (broadcast, unknown unicast).
* When the port is not under a bridge, only the CTRL interface is part * When the port is not under a bridge, only the CTRL interface is part
* of the flooding domain besides the actual port * of the flooding domain besides the actual port
...@@ -1583,6 +1698,11 @@ static int dpaa2_switch_port_bridge_leave(struct net_device *netdev) ...@@ -1583,6 +1698,11 @@ static int dpaa2_switch_port_bridge_leave(struct net_device *netdev)
if (err) if (err)
return err; return err;
/* No HW learning when not under a bridge */
err = dpaa2_switch_port_set_learning(port_priv, false);
if (err)
return err;
/* Add the VLAN 1 as PVID when not under a bridge. We need this since /* Add the VLAN 1 as PVID when not under a bridge. We need this since
* the dpaa2 switch interfaces are not capable to be VLAN unaware * the dpaa2 switch interfaces are not capable to be VLAN unaware
*/ */
...@@ -1885,6 +2005,9 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq, ...@@ -1885,6 +2005,9 @@ static void dpaa2_switch_rx(struct dpaa2_switch_fq *fq,
skb->dev = netdev; skb->dev = netdev;
skb->protocol = eth_type_trans(skb, skb->dev); skb->protocol = eth_type_trans(skb, skb->dev);
/* Setup the offload_fwd_mark only if the port is under a bridge */
skb->offload_fwd_mark = !!(port_priv->fdb->bridge_dev);
netif_receive_skb(skb); netif_receive_skb(skb);
return; return;
...@@ -2650,6 +2773,9 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw, ...@@ -2650,6 +2773,9 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
port_netdev->needed_headroom = DPAA2_SWITCH_NEEDED_HEADROOM; port_netdev->needed_headroom = DPAA2_SWITCH_NEEDED_HEADROOM;
port_priv->bcast_flood = true;
port_priv->ucast_flood = true;
/* Set MTU limits */ /* Set MTU limits */
port_netdev->min_mtu = ETH_MIN_MTU; port_netdev->min_mtu = ETH_MIN_MTU;
port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH; port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH;
...@@ -2672,6 +2798,10 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw, ...@@ -2672,6 +2798,10 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
if (err) if (err)
goto err_port_probe; goto err_port_probe;
err = dpaa2_switch_port_set_learning(port_priv, false);
if (err)
goto err_port_probe;
return 0; return 0;
err_port_probe: err_port_probe:
......
...@@ -105,13 +105,14 @@ struct ethsw_port_priv { ...@@ -105,13 +105,14 @@ struct ethsw_port_priv {
struct ethsw_core *ethsw_data; struct ethsw_core *ethsw_data;
u8 link_state; u8 link_state;
u8 stp_state; u8 stp_state;
bool flood;
u8 vlans[VLAN_VID_MASK + 1]; u8 vlans[VLAN_VID_MASK + 1];
u16 pvid; u16 pvid;
u16 tx_qdid; u16 tx_qdid;
struct dpaa2_switch_fdb *fdb; struct dpaa2_switch_fdb *fdb;
bool bcast_flood;
bool ucast_flood;
}; };
/* Switch data */ /* Switch data */
......
...@@ -83,6 +83,7 @@ ...@@ -83,6 +83,7 @@
#define DPSW_CMDID_CTRL_IF_SET_QUEUE DPSW_CMD_ID(0x0A6) #define DPSW_CMDID_CTRL_IF_SET_QUEUE DPSW_CMD_ID(0x0A6)
#define DPSW_CMDID_SET_EGRESS_FLOOD DPSW_CMD_ID(0x0AC) #define DPSW_CMDID_SET_EGRESS_FLOOD DPSW_CMD_ID(0x0AC)
#define DPSW_CMDID_IF_SET_LEARNING_MODE DPSW_CMD_ID(0x0AD)
/* Macros for accessing command fields smaller than 1byte */ /* Macros for accessing command fields smaller than 1byte */
#define DPSW_MASK(field) \ #define DPSW_MASK(field) \
...@@ -447,5 +448,14 @@ struct dpsw_cmd_set_egress_flood { ...@@ -447,5 +448,14 @@ struct dpsw_cmd_set_egress_flood {
u8 pad[5]; u8 pad[5];
__le64 if_id; __le64 if_id;
}; };
#define DPSW_LEARNING_MODE_SHIFT 0
#define DPSW_LEARNING_MODE_SIZE 4
struct dpsw_cmd_if_set_learning_mode {
__le16 if_id;
/* only the first 4 bits from LSB */
u8 mode;
};
#pragma pack(pop) #pragma pack(pop)
#endif /* __FSL_DPSW_CMD_H */ #endif /* __FSL_DPSW_CMD_H */
...@@ -1327,3 +1327,30 @@ int dpsw_set_egress_flood(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ...@@ -1327,3 +1327,30 @@ int dpsw_set_egress_flood(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
return mc_send_command(mc_io, &cmd); return mc_send_command(mc_io, &cmd);
} }
/**
* dpsw_if_set_learning_mode() - Configure the learning mode on an interface.
* If this API is used, it will take precedence over the FDB configuration.
* @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: InterfaceID
* @mode: Learning mode
*
* Return: Completion status. '0' on Success; Error code otherwise.
*/
int dpsw_if_set_learning_mode(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id, enum dpsw_learning_mode mode)
{
struct dpsw_cmd_if_set_learning_mode *cmd_params;
struct fsl_mc_command cmd = { 0 };
cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_SET_LEARNING_MODE,
cmd_flags,
token);
cmd_params = (struct dpsw_cmd_if_set_learning_mode *)cmd.params;
cmd_params->if_id = cpu_to_le16(if_id);
dpsw_set_field(cmd_params->mode, LEARNING_MODE, mode);
return mc_send_command(mc_io, &cmd);
}
...@@ -532,11 +532,11 @@ int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ...@@ -532,11 +532,11 @@ int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 fdb_id, const struct dpsw_fdb_multicast_cfg *cfg); u16 fdb_id, const struct dpsw_fdb_multicast_cfg *cfg);
/** /**
* enum dpsw_fdb_learning_mode - Auto-learning modes * enum dpsw_learning_mode - Auto-learning modes
* @DPSW_FDB_LEARNING_MODE_DIS: Disable Auto-learning * @DPSW_LEARNING_MODE_DIS: Disable Auto-learning
* @DPSW_FDB_LEARNING_MODE_HW: Enable HW auto-Learning * @DPSW_LEARNING_MODE_HW: Enable HW auto-Learning
* @DPSW_FDB_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU * @DPSW_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU
* @DPSW_FDB_LEARNING_MODE_SECURE: Enable secure learning by CPU * @DPSW_LEARNING_MODE_SECURE: Enable secure learning by CPU
* *
* NONE - SECURE LEARNING * NONE - SECURE LEARNING
* SMAC found DMAC found CTLU Action * SMAC found DMAC found CTLU Action
...@@ -561,11 +561,11 @@ int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, ...@@ -561,11 +561,11 @@ int dpsw_fdb_remove_multicast(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
* - - Forward frame to * - - Forward frame to
* 1. Control interface * 1. Control interface
*/ */
enum dpsw_fdb_learning_mode { enum dpsw_learning_mode {
DPSW_FDB_LEARNING_MODE_DIS = 0, DPSW_LEARNING_MODE_DIS = 0,
DPSW_FDB_LEARNING_MODE_HW = 1, DPSW_LEARNING_MODE_HW = 1,
DPSW_FDB_LEARNING_MODE_NON_SECURE = 2, DPSW_LEARNING_MODE_NON_SECURE = 2,
DPSW_FDB_LEARNING_MODE_SECURE = 3 DPSW_LEARNING_MODE_SECURE = 3
}; };
/** /**
...@@ -579,7 +579,7 @@ enum dpsw_fdb_learning_mode { ...@@ -579,7 +579,7 @@ enum dpsw_fdb_learning_mode {
struct dpsw_fdb_attr { struct dpsw_fdb_attr {
u16 max_fdb_entries; u16 max_fdb_entries;
u16 fdb_ageing_time; u16 fdb_ageing_time;
enum dpsw_fdb_learning_mode learning_mode; enum dpsw_learning_mode learning_mode;
u16 num_fdb_mc_groups; u16 num_fdb_mc_groups;
u16 max_fdb_mc_groups; u16 max_fdb_mc_groups;
}; };
...@@ -625,4 +625,7 @@ struct dpsw_egress_flood_cfg { ...@@ -625,4 +625,7 @@ struct dpsw_egress_flood_cfg {
int dpsw_set_egress_flood(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, int dpsw_set_egress_flood(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
const struct dpsw_egress_flood_cfg *cfg); const struct dpsw_egress_flood_cfg *cfg);
int dpsw_if_set_learning_mode(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
u16 if_id, enum dpsw_learning_mode mode);
#endif /* __FSL_DPSW_H */ #endif /* __FSL_DPSW_H */
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