Commit db7284a6 authored by Kurt Kanzenbach's avatar Kurt Kanzenbach Committed by David S. Miller
Browse files

net: dsa: hellcreek: Offload bridge port flags



The switch implements unicast and multicast filtering per port.
Add support for it. By default filtering is disabled.

Signed-off-by: default avatarKurt Kanzenbach <kurt@kmk-computers.de>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2117fce8
Loading
Loading
Loading
Loading
+104 −25
Original line number Diff line number Diff line
@@ -596,6 +596,83 @@ static void hellcreek_setup_vlan_membership(struct dsa_switch *ds, int port,
		hellcreek_unapply_vlan(hellcreek, upstream, vid);
}

static void hellcreek_port_set_ucast_flood(struct hellcreek *hellcreek,
					   int port, bool enable)
{
	struct hellcreek_port *hellcreek_port;
	u16 val;

	hellcreek_port = &hellcreek->ports[port];

	dev_dbg(hellcreek->dev, "%s unicast flooding on port %d\n",
		enable ? "Enable" : "Disable", port);

	mutex_lock(&hellcreek->reg_lock);

	hellcreek_select_port(hellcreek, port);
	val = hellcreek_port->ptcfg;
	if (enable)
		val &= ~HR_PTCFG_UUC_FLT;
	else
		val |= HR_PTCFG_UUC_FLT;
	hellcreek_write(hellcreek, val, HR_PTCFG);
	hellcreek_port->ptcfg = val;

	mutex_unlock(&hellcreek->reg_lock);
}

static void hellcreek_port_set_mcast_flood(struct hellcreek *hellcreek,
					   int port, bool enable)
{
	struct hellcreek_port *hellcreek_port;
	u16 val;

	hellcreek_port = &hellcreek->ports[port];

	dev_dbg(hellcreek->dev, "%s multicast flooding on port %d\n",
		enable ? "Enable" : "Disable", port);

	mutex_lock(&hellcreek->reg_lock);

	hellcreek_select_port(hellcreek, port);
	val = hellcreek_port->ptcfg;
	if (enable)
		val &= ~HR_PTCFG_UMC_FLT;
	else
		val |= HR_PTCFG_UMC_FLT;
	hellcreek_write(hellcreek, val, HR_PTCFG);
	hellcreek_port->ptcfg = val;

	mutex_unlock(&hellcreek->reg_lock);
}

static int hellcreek_pre_bridge_flags(struct dsa_switch *ds, int port,
				      struct switchdev_brport_flags flags,
				      struct netlink_ext_ack *extack)
{
	if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD))
		return -EINVAL;

	return 0;
}

static int hellcreek_bridge_flags(struct dsa_switch *ds, int port,
				  struct switchdev_brport_flags flags,
				  struct netlink_ext_ack *extack)
{
	struct hellcreek *hellcreek = ds->priv;

	if (flags.mask & BR_FLOOD)
		hellcreek_port_set_ucast_flood(hellcreek, port,
					       !!(flags.val & BR_FLOOD));

	if (flags.mask & BR_MCAST_FLOOD)
		hellcreek_port_set_mcast_flood(hellcreek, port,
					       !!(flags.val & BR_MCAST_FLOOD));

	return 0;
}

static int hellcreek_port_bridge_join(struct dsa_switch *ds, int port,
				      struct net_device *br)
{
@@ -1661,6 +1738,7 @@ static const struct dsa_switch_ops hellcreek_ds_ops = {
	.get_tag_protocol      = hellcreek_get_tag_protocol,
	.get_ts_info	       = hellcreek_get_ts_info,
	.phylink_validate      = hellcreek_phylink_validate,
	.port_bridge_flags     = hellcreek_bridge_flags,
	.port_bridge_join      = hellcreek_port_bridge_join,
	.port_bridge_leave     = hellcreek_port_bridge_leave,
	.port_disable	       = hellcreek_port_disable,
@@ -1670,6 +1748,7 @@ static const struct dsa_switch_ops hellcreek_ds_ops = {
	.port_fdb_dump	       = hellcreek_fdb_dump,
	.port_hwtstamp_set     = hellcreek_port_hwtstamp_set,
	.port_hwtstamp_get     = hellcreek_port_hwtstamp_get,
	.port_pre_bridge_flags = hellcreek_pre_bridge_flags,
	.port_prechangeupper   = hellcreek_port_prechangeupper,
	.port_rxtstamp	       = hellcreek_port_rxtstamp,
	.port_setup_tc	       = hellcreek_port_setup_tc,