Commit 539dda3c authored by Ioana Ciornei's avatar Ioana Ciornei Committed by David S. Miller

staging: dpaa2-switch: properly setup switching domains

Until now, the DPAA2 switch was not capable to properly setup its
switching domains depending on the existence, or lack thereof, of a
upper bridge device. This meant that all switch ports of a DPSW object
were switching by default even though they were not under the same
bridge device.

Another issue was the inability to actually add the CPU in the flooding
domains (broadcast, unknown unicast etc) of a particular switch port.
This meant that a simple ping on a switch interface was not possible
since no broadcast ARP frame would actually reach the CPU queues.

This patch tries to fix exactly these problems by:

* Creating and managing a FDB table for each flooding domain. This means
  that when a switch interface is not bridged it will use its own FDB
  table. While in bridged mode all DPAA2 switch interfaces under the
  same upper will use the same FDB table, thus leverage the same FDB
  entries.

* Adding a new MC firmware command - dpsw_set_egress_flood() - through
  which the driver can setup the flooding domains as needed. For
  example, when the switch interface is standalone, thus not in a
  bridge with any other DPAA2 switch port, it will setup its broadcast
  and unknown unicast flooding domains to only include the control
  interface (the queues that reach the CPU and the driver can dequeue
  from). This flooding domain changes when the interface joins a bridge
  and is configured to include, beside the control interface, all other
  DPAA2 switch interfaces.

We impose a minimum limit of FDB tables available equal to the number of
switch interfaces so that we guarantee that, in the maximal
configuration - all interfaces are standalone, each switch port will
have a private FDB table. At the same time, we only probe DPSW objects
that have the flooding and broadcast replicators configured to be per
FDB (DPSW_*_PER_FDB). Without this, the dpaa2-switch driver would not
be able to configure multiple switching domains.

At probe time, a FDB table will be allocated for each port. At a bridge
join event, the switch port will either continue to use the current FDB
table (if it's the first dpaa2-switch port to join that bridge) or will
switch to use the FDB table associated with the port that it's already
under the bridge. If a FDB switch is necessary, the private FDB table
which was previously used will be returned to the pool of unused FDBs.

Upon a bridge leave, the switch port needs a private FDB table thus it
will search and get the first unused FDB table. This way, all the other
ports remaining under the bridge will continue to use the same FDB
table.
Signed-off-by: default avatarIoana Ciornei <ioana.ciornei@nxp.com>
Reviewed-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 613c0a58
......@@ -29,7 +29,7 @@
#define DPSW_CMDID_ENABLE DPSW_CMD_ID(0x002)
#define DPSW_CMDID_DISABLE DPSW_CMD_ID(0x003)
#define DPSW_CMDID_GET_ATTR DPSW_CMD_ID(0x004)
#define DPSW_CMDID_GET_ATTR DPSW_CMD_V2(0x004)
#define DPSW_CMDID_RESET DPSW_CMD_ID(0x005)
#define DPSW_CMDID_SET_IRQ_ENABLE DPSW_CMD_ID(0x012)
......@@ -58,7 +58,7 @@
#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_IF DPSW_CMD_ID(0x061)
#define DPSW_CMDID_VLAN_ADD_IF DPSW_CMD_V2(0x061)
#define DPSW_CMDID_VLAN_ADD_IF_UNTAGGED DPSW_CMD_ID(0x062)
#define DPSW_CMDID_VLAN_REMOVE_IF DPSW_CMD_ID(0x064)
......@@ -66,6 +66,8 @@
#define DPSW_CMDID_VLAN_REMOVE_IF_FLOODING DPSW_CMD_ID(0x066)
#define DPSW_CMDID_VLAN_REMOVE DPSW_CMD_ID(0x067)
#define DPSW_CMDID_FDB_ADD DPSW_CMD_ID(0x082)
#define DPSW_CMDID_FDB_REMOVE DPSW_CMD_ID(0x083)
#define DPSW_CMDID_FDB_ADD_UNICAST DPSW_CMD_ID(0x084)
#define DPSW_CMDID_FDB_REMOVE_UNICAST DPSW_CMD_ID(0x085)
#define DPSW_CMDID_FDB_ADD_MULTICAST DPSW_CMD_ID(0x086)
......@@ -82,6 +84,8 @@
#define DPSW_CMDID_CTRL_IF_DISABLE DPSW_CMD_ID(0x0A3)
#define DPSW_CMDID_CTRL_IF_SET_QUEUE DPSW_CMD_ID(0x0A6)
#define DPSW_CMDID_SET_EGRESS_FLOOD DPSW_CMD_ID(0x0AC)
/* Macros for accessing command fields smaller than 1byte */
#define DPSW_MASK(field) \
GENMASK(DPSW_##field##_SHIFT + DPSW_##field##_SIZE - 1, \
......@@ -176,6 +180,12 @@ struct dpsw_cmd_clear_irq_status {
#define DPSW_COMPONENT_TYPE_SHIFT 0
#define DPSW_COMPONENT_TYPE_SIZE 4
#define DPSW_FLOODING_CFG_SHIFT 0
#define DPSW_FLOODING_CFG_SIZE 4
#define DPSW_BROADCAST_CFG_SHIFT 4
#define DPSW_BROADCAST_CFG_SIZE 4
struct dpsw_rsp_get_attr {
/* cmd word 0 */
__le16 num_ifs;
......@@ -193,7 +203,11 @@ struct dpsw_rsp_get_attr {
u8 max_meters_per_if;
/* from LSB only the first 4 bits */
u8 component_type;
__le16 pad;
/* [0:3] - flooding configuration
* [4:7] - broadcast configuration
*/
u8 repl_cfg;
u8 pad;
/* cmd word 3 */
__le64 options;
};
......@@ -312,6 +326,16 @@ struct dpsw_vlan_add {
__le16 vlan_id;
};
struct dpsw_cmd_vlan_add_if {
/* cmd word 0 */
__le16 options;
__le16 vlan_id;
__le16 fdb_id;
__le16 pad0;
/* cmd word 1-4 */
__le64 if_id;
};
struct dpsw_cmd_vlan_manage_if {
/* cmd word 0 */
__le16 pad0;
......@@ -328,7 +352,7 @@ struct dpsw_cmd_vlan_remove {
struct dpsw_cmd_fdb_add {
__le32 pad;
__le16 fdb_aging_time;
__le16 fdb_ageing_time;
__le16 num_fdb_entries;
};
......@@ -424,5 +448,11 @@ struct dpsw_cmd_if_set_mac_addr {
u8 mac_addr[6];
};
struct dpsw_cmd_set_egress_flood {
__le16 fdb_id;
u8 flood_type;
u8 pad[5];
__le64 if_id;
};
#pragma pack(pop)
#endif /* __FSL_DPSW_CMD_H */
......@@ -351,9 +351,9 @@ int dpsw_get_attributes(struct fsl_mc_io *mc_io,
attr->max_fdb_mc_groups = le16_to_cpu(rsp_params->max_fdb_mc_groups);
attr->max_meters_per_if = rsp_params->max_meters_per_if;
attr->options = le64_to_cpu(rsp_params->options);
attr->component_type = dpsw_get_field(rsp_params->component_type,
COMPONENT_TYPE);
attr->component_type = dpsw_get_field(rsp_params->component_type, COMPONENT_TYPE);
attr->flooding_cfg = dpsw_get_field(rsp_params->repl_cfg, FLOODING_CFG);
attr->broadcast_cfg = dpsw_get_field(rsp_params->repl_cfg, BROADCAST_CFG);
return 0;
}
......@@ -924,6 +924,66 @@ int dpsw_vlan_remove(struct fsl_mc_io *mc_io,
return mc_send_command(mc_io, &cmd);
}
/**
* dpsw_fdb_add() - Add FDB to switch and Returns handle to FDB table for
* the reference
* @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
* @fdb_id: Returned Forwarding Database Identifier
* @cfg: FDB Configuration
*
* Return: Completion status. '0' on Success; Error code otherwise.
*/
int dpsw_fdb_add(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u16 *fdb_id,
const struct dpsw_fdb_cfg *cfg)
{
struct dpsw_cmd_fdb_add *cmd_params;
struct dpsw_rsp_fdb_add *rsp_params;
struct fsl_mc_command cmd = { 0 };
int err;
cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_ADD,
cmd_flags,
token);
cmd_params = (struct dpsw_cmd_fdb_add *)cmd.params;
cmd_params->fdb_ageing_time = cpu_to_le16(cfg->fdb_ageing_time);
cmd_params->num_fdb_entries = cpu_to_le16(cfg->num_fdb_entries);
err = mc_send_command(mc_io, &cmd);
if (err)
return err;
rsp_params = (struct dpsw_rsp_fdb_add *)cmd.params;
*fdb_id = le16_to_cpu(rsp_params->fdb_id);
return 0;
}
/**
* dpsw_fdb_remove() - Remove FDB from switch
* @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
* @fdb_id: Forwarding Database Identifier
*
* Return: Completion status. '0' on Success; Error code otherwise.
*/
int dpsw_fdb_remove(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u16 fdb_id)
{
struct dpsw_cmd_fdb_remove *cmd_params;
struct fsl_mc_command cmd = { 0 };
/* prepare command */
cmd.header = mc_encode_cmd_header(DPSW_CMDID_FDB_REMOVE,
cmd_flags,
token);
cmd_params = (struct dpsw_cmd_fdb_remove *)cmd.params;
cmd_params->fdb_id = cpu_to_le16(fdb_id);
return mc_send_command(mc_io, &cmd);
}
/**
* dpsw_fdb_add_unicast() - Function adds an unicast entry into MAC lookup table
* @mc_io: Pointer to MC portal's I/O object
......@@ -1400,3 +1460,27 @@ int dpsw_ctrl_if_disable(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token)
return mc_send_command(mc_io, &cmd);
}
/**
* dpsw_set_egress_flood() - Set egress parameters associated with an FDB ID
* @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
* @cfg: Egress flooding configuration
*
* Return: '0' on Success; Error code otherwise.
*/
int dpsw_set_egress_flood(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
const struct dpsw_egress_flood_cfg *cfg)
{
struct dpsw_cmd_set_egress_flood *cmd_params;
struct fsl_mc_command cmd = { 0 };
cmd.header = mc_encode_cmd_header(DPSW_CMDID_SET_EGRESS_FLOOD, cmd_flags, token);
cmd_params = (struct dpsw_cmd_set_egress_flood *)cmd.params;
cmd_params->fdb_id = cpu_to_le16(cfg->fdb_id);
cmd_params->flood_type = cfg->flood_type;
build_if_id_bitmap(&cmd_params->if_id, cfg->if_id, cfg->num_ifs);
return mc_send_command(mc_io, &cmd);
}
......@@ -75,6 +75,35 @@ enum dpsw_component_type {
DPSW_COMPONENT_TYPE_S_VLAN
};
/**
* enum dpsw_flooding_cfg - flooding configuration requested
* @DPSW_FLOODING_PER_VLAN: Flooding replicators are allocated per VLAN and
* interfaces present in each of them can be configured using
* dpsw_vlan_add_if_flooding()/dpsw_vlan_remove_if_flooding().
* This is the default configuration.
*
* @DPSW_FLOODING_PER_FDB: Flooding replicators are allocated per FDB and
* interfaces present in each of them can be configured using
* dpsw_set_egress_flood().
*/
enum dpsw_flooding_cfg {
DPSW_FLOODING_PER_VLAN = 0,
DPSW_FLOODING_PER_FDB,
};
/**
* enum dpsw_broadcast_cfg - broadcast configuration requested
* @DPSW_BROADCAST_PER_OBJECT: There is only one broadcast replicator per DPSW
* object. This is the default configuration.
* @DPSW_BROADCAST_PER_FDB: Broadcast replicators are allocated per FDB and
* interfaces present in each of them can be configured using
* dpsw_set_egress_flood().
*/
enum dpsw_broadcast_cfg {
DPSW_BROADCAST_PER_OBJECT = 0,
DPSW_BROADCAST_PER_FDB,
};
int dpsw_enable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token);
......@@ -153,6 +182,8 @@ int dpsw_clear_irq_status(struct fsl_mc_io *mc_io,
* @num_vlans: Current number of VLANs
* @num_fdbs: Current number of FDBs
* @component_type: Component type of this bridge
* @flooding_cfg: Flooding configuration (PER_VLAN - default, PER_FDB)
* @broadcast_cfg: Broadcast configuration (PER_OBJECT - default, PER_FDB)
*/
struct dpsw_attr {
int id;
......@@ -168,6 +199,8 @@ struct dpsw_attr {
u16 num_vlans;
u8 num_fdbs;
enum dpsw_component_type component_type;
enum dpsw_flooding_cfg flooding_cfg;
enum dpsw_broadcast_cfg broadcast_cfg;
};
int dpsw_get_attributes(struct fsl_mc_io *mc_io,
......@@ -483,6 +516,8 @@ int dpsw_vlan_add(struct fsl_mc_io *mc_io,
u16 vlan_id,
const struct dpsw_vlan_cfg *cfg);
#define DPSW_VLAN_ADD_IF_OPT_FDB_ID 0x0001
/**
* struct dpsw_vlan_if_cfg - Set of VLAN Interfaces
* @num_ifs: The number of interfaces that are assigned to the egress
......@@ -492,7 +527,9 @@ int dpsw_vlan_add(struct fsl_mc_io *mc_io,
*/
struct dpsw_vlan_if_cfg {
u16 num_ifs;
u16 options;
u16 if_id[DPSW_MAX_IF];
u16 fdb_id;
};
int dpsw_vlan_add_if(struct fsl_mc_io *mc_io,
......@@ -649,14 +686,14 @@ enum dpsw_fdb_learning_mode {
/**
* struct dpsw_fdb_attr - FDB Attributes
* @max_fdb_entries: Number of FDB entries
* @fdb_aging_time: Aging time in seconds
* @fdb_ageing_time: Ageing time in seconds
* @learning_mode: Learning mode
* @num_fdb_mc_groups: Current number of multicast groups
* @max_fdb_mc_groups: Maximum number of multicast groups
*/
struct dpsw_fdb_attr {
u16 max_fdb_entries;
u16 fdb_aging_time;
u16 fdb_ageing_time;
enum dpsw_fdb_learning_mode learning_mode;
u16 num_fdb_mc_groups;
u16 max_fdb_mc_groups;
......@@ -676,4 +713,39 @@ int dpsw_if_get_primary_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags,
int dpsw_if_set_primary_mac_addr(struct fsl_mc_io *mc_io, u32 cmd_flags,
u16 token, u16 if_id, u8 mac_addr[6]);
/**
* struct dpsw_fdb_cfg - FDB Configuration
* @num_fdb_entries: Number of FDB entries
* @fdb_ageing_time: Ageing time in seconds
*/
struct dpsw_fdb_cfg {
u16 num_fdb_entries;
u16 fdb_ageing_time;
};
int dpsw_fdb_add(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u16 *fdb_id,
const struct dpsw_fdb_cfg *cfg);
int dpsw_fdb_remove(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token, u16 fdb_id);
/**
* enum dpsw_flood_type - Define the flood type of a DPSW object
* @DPSW_BROADCAST: Broadcast flooding
* @DPSW_FLOODING: Unknown flooding
*/
enum dpsw_flood_type {
DPSW_BROADCAST = 0,
DPSW_FLOODING,
};
struct dpsw_egress_flood_cfg {
u16 fdb_id;
enum dpsw_flood_type flood_type;
u16 num_ifs;
u16 if_id[DPSW_MAX_IF];
};
int dpsw_set_egress_flood(struct fsl_mc_io *mc_io, u32 cmd_flags, u16 token,
const struct dpsw_egress_flood_cfg *cfg);
#endif /* __FSL_DPSW_H */
This diff is collapsed.
......@@ -92,6 +92,12 @@ struct dpaa2_switch_fq {
u32 fqid;
};
struct dpaa2_switch_fdb {
struct net_device *bridge_dev;
u16 fdb_id;
bool in_use;
};
/* Per port private data */
struct ethsw_port_priv {
struct net_device *netdev;
......@@ -103,8 +109,9 @@ struct ethsw_port_priv {
u8 vlans[VLAN_VID_MASK + 1];
u16 pvid;
struct net_device *bridge_dev;
u16 tx_qdid;
struct dpaa2_switch_fdb *fdb;
};
/* Switch data */
......@@ -131,6 +138,8 @@ struct ethsw_core {
int buf_count;
u16 bpid;
int napi_users;
struct dpaa2_switch_fdb *fdbs;
};
static inline bool dpaa2_switch_supports_cpu_traffic(struct ethsw_core *ethsw)
......@@ -140,6 +149,25 @@ static inline bool dpaa2_switch_supports_cpu_traffic(struct ethsw_core *ethsw)
return false;
}
if (ethsw->sw_attr.flooding_cfg != DPSW_FLOODING_PER_FDB) {
dev_err(ethsw->dev, "Flooding domain is not per FDB, cannot probe\n");
return false;
}
if (ethsw->sw_attr.broadcast_cfg != DPSW_BROADCAST_PER_FDB) {
dev_err(ethsw->dev, "Broadcast domain is not per FDB, cannot probe\n");
return false;
}
if (ethsw->sw_attr.max_fdbs < ethsw->sw_attr.num_ifs) {
dev_err(ethsw->dev, "The number of FDBs is lower than the number of ports, cannot probe\n");
return false;
}
return true;
}
bool dpaa2_switch_port_dev_check(const struct net_device *netdev,
struct notifier_block *nb);
#endif /* __ETHSW_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