mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 05:33:09 +00:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0ca99c84df
@ -110,6 +110,63 @@ static u16 dpaa2_switch_port_set_fdb(struct ethsw_port_priv *port_priv,
|
||||
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,
|
||||
dma_addr_t iova_addr)
|
||||
{
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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,
|
||||
const struct switchdev_attr *attr,
|
||||
struct netlink_ext_ack *extack)
|
||||
@ -1202,6 +1341,12 @@ static int dpaa2_switch_port_attr_set(struct net_device *netdev,
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
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:
|
||||
err = -EOPNOTSUPP;
|
||||
break;
|
||||
@ -1442,48 +1587,6 @@ static int dpaa2_switch_port_attr_set_event(struct net_device *netdev,
|
||||
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,
|
||||
struct net_device *upper_dev)
|
||||
{
|
||||
@ -1492,6 +1595,7 @@ static int dpaa2_switch_port_bridge_join(struct net_device *netdev,
|
||||
struct ethsw_port_priv *other_port_priv;
|
||||
struct net_device *other_dev;
|
||||
struct list_head *iter;
|
||||
bool learn_ena;
|
||||
int err;
|
||||
|
||||
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,
|
||||
|
||||
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) */
|
||||
err = dpaa2_switch_fdb_set_egress_flood(ethsw, port_priv->fdb->fdb_id);
|
||||
if (err)
|
||||
@ -1570,6 +1678,13 @@ static int dpaa2_switch_port_bridge_leave(struct net_device *netdev)
|
||||
if (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).
|
||||
* When the port is not under a bridge, only the CTRL interface is part
|
||||
* of the flooding domain besides the actual port
|
||||
@ -1583,6 +1698,11 @@ static int dpaa2_switch_port_bridge_leave(struct net_device *netdev)
|
||||
if (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
|
||||
* 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,
|
||||
skb->dev = netdev;
|
||||
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);
|
||||
|
||||
return;
|
||||
@ -2650,6 +2773,9 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
|
||||
|
||||
port_netdev->needed_headroom = DPAA2_SWITCH_NEEDED_HEADROOM;
|
||||
|
||||
port_priv->bcast_flood = true;
|
||||
port_priv->ucast_flood = true;
|
||||
|
||||
/* Set MTU limits */
|
||||
port_netdev->min_mtu = ETH_MIN_MTU;
|
||||
port_netdev->max_mtu = ETHSW_MAX_FRAME_LENGTH;
|
||||
@ -2672,6 +2798,10 @@ static int dpaa2_switch_probe_port(struct ethsw_core *ethsw,
|
||||
if (err)
|
||||
goto err_port_probe;
|
||||
|
||||
err = dpaa2_switch_port_set_learning(port_priv, false);
|
||||
if (err)
|
||||
goto err_port_probe;
|
||||
|
||||
return 0;
|
||||
|
||||
err_port_probe:
|
||||
|
@ -105,13 +105,14 @@ struct ethsw_port_priv {
|
||||
struct ethsw_core *ethsw_data;
|
||||
u8 link_state;
|
||||
u8 stp_state;
|
||||
bool flood;
|
||||
|
||||
u8 vlans[VLAN_VID_MASK + 1];
|
||||
u16 pvid;
|
||||
u16 tx_qdid;
|
||||
|
||||
struct dpaa2_switch_fdb *fdb;
|
||||
bool bcast_flood;
|
||||
bool ucast_flood;
|
||||
};
|
||||
|
||||
/* Switch data */
|
||||
|
@ -83,6 +83,7 @@
|
||||
#define DPSW_CMDID_CTRL_IF_SET_QUEUE DPSW_CMD_ID(0x0A6)
|
||||
|
||||
#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 */
|
||||
#define DPSW_MASK(field) \
|
||||
@ -447,5 +448,14 @@ struct dpsw_cmd_set_egress_flood {
|
||||
u8 pad[5];
|
||||
__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)
|
||||
#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,
|
||||
|
||||
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,
|
||||
u16 fdb_id, const struct dpsw_fdb_multicast_cfg *cfg);
|
||||
|
||||
/**
|
||||
* enum dpsw_fdb_learning_mode - Auto-learning modes
|
||||
* @DPSW_FDB_LEARNING_MODE_DIS: Disable Auto-learning
|
||||
* @DPSW_FDB_LEARNING_MODE_HW: Enable HW auto-Learning
|
||||
* @DPSW_FDB_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU
|
||||
* @DPSW_FDB_LEARNING_MODE_SECURE: Enable secure learning by CPU
|
||||
* enum dpsw_learning_mode - Auto-learning modes
|
||||
* @DPSW_LEARNING_MODE_DIS: Disable Auto-learning
|
||||
* @DPSW_LEARNING_MODE_HW: Enable HW auto-Learning
|
||||
* @DPSW_LEARNING_MODE_NON_SECURE: Enable None secure learning by CPU
|
||||
* @DPSW_LEARNING_MODE_SECURE: Enable secure learning by CPU
|
||||
*
|
||||
* NONE - SECURE LEARNING
|
||||
* 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,
|
||||
* - - Forward frame to
|
||||
* 1. Control interface
|
||||
*/
|
||||
enum dpsw_fdb_learning_mode {
|
||||
DPSW_FDB_LEARNING_MODE_DIS = 0,
|
||||
DPSW_FDB_LEARNING_MODE_HW = 1,
|
||||
DPSW_FDB_LEARNING_MODE_NON_SECURE = 2,
|
||||
DPSW_FDB_LEARNING_MODE_SECURE = 3
|
||||
enum dpsw_learning_mode {
|
||||
DPSW_LEARNING_MODE_DIS = 0,
|
||||
DPSW_LEARNING_MODE_HW = 1,
|
||||
DPSW_LEARNING_MODE_NON_SECURE = 2,
|
||||
DPSW_LEARNING_MODE_SECURE = 3
|
||||
};
|
||||
|
||||
/**
|
||||
@ -579,7 +579,7 @@ enum dpsw_fdb_learning_mode {
|
||||
struct dpsw_fdb_attr {
|
||||
u16 max_fdb_entries;
|
||||
u16 fdb_ageing_time;
|
||||
enum dpsw_fdb_learning_mode learning_mode;
|
||||
enum dpsw_learning_mode learning_mode;
|
||||
u16 num_fdb_mc_groups;
|
||||
u16 max_fdb_mc_groups;
|
||||
};
|
||||
@ -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,
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user