Commit 161087db authored by MD Danish Anwar's avatar MD Danish Anwar Committed by Paolo Abeni
Browse files

net: ti: icssg-prueth: Add Support for Multicast filtering with VLAN in HSR mode



Add multicast filtering support for VLAN interfaces in HSR offload mode
for ICSSG driver.

The driver calls vlan_for_each() API on the hsr device's ndev to get the
list of available vlans for the hsr device. The driver then sync mc addr of
vlan interface with a locally mainatined list emac->vlan_mcast_list[vid]
using __hw_addr_sync_multiple() API.

The driver then calls the sync / unsync callbacks.

In the sync / unsync call back, driver checks if the vdev's real dev is
hsr device or not. If the real dev is hsr device, driver gets the per
port device using hsr_get_port_ndev() and then driver passes appropriate
vid to FDB helper functions.

Signed-off-by: default avatarMD Danish Anwar <danishanwar@ti.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 9c10dd8e
Loading
Loading
Loading
Loading
+64 −19
Original line number Diff line number Diff line
@@ -604,32 +604,66 @@ static int icssg_prueth_del_mcast(struct net_device *ndev, const u8 *addr)
	return 0;
}

static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
static void icssg_prueth_hsr_fdb_add_del(struct prueth_emac *emac,
					 const u8 *addr, u8 vid, bool add)
{
	struct prueth_emac *emac = netdev_priv(ndev);
	struct prueth *prueth = emac->prueth;

	icssg_fdb_add_del(emac, addr, prueth->default_vlan,
	icssg_fdb_add_del(emac, addr, vid,
			  ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
			  ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
			  ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
			  ICSSG_FDB_ENTRY_BLOCK, true);
			  ICSSG_FDB_ENTRY_BLOCK, add);

	if (add)
		icssg_vtbl_modify(emac, vid, BIT(emac->port_id),
				  BIT(emac->port_id), add);
}

static int icssg_prueth_hsr_add_mcast(struct net_device *ndev, const u8 *addr)
{
	struct net_device *real_dev;
	struct prueth_emac *emac;
	u8 vlan_id, i;

	vlan_id = is_vlan_dev(ndev) ? vlan_dev_vlan_id(ndev) : PRUETH_DFLT_VLAN_HSR;
	real_dev = is_vlan_dev(ndev) ? vlan_dev_real_dev(ndev) : ndev;

	if (is_hsr_master(real_dev)) {
		for (i = HSR_PT_SLAVE_A; i < HSR_PT_INTERLINK; i++) {
			emac = netdev_priv(hsr_get_port_ndev(real_dev, i));
			if (!emac)
				return -EINVAL;
			icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id,
						     true);
		}
	} else {
		emac = netdev_priv(real_dev);
		icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id, true);
	}

	icssg_vtbl_modify(emac, emac->port_vlan, BIT(emac->port_id),
			  BIT(emac->port_id), true);
	return 0;
}

static int icssg_prueth_hsr_del_mcast(struct net_device *ndev, const u8 *addr)
{
	struct prueth_emac *emac = netdev_priv(ndev);
	struct prueth *prueth = emac->prueth;
	struct net_device *real_dev;
	struct prueth_emac *emac;
	u8 vlan_id, i;

	icssg_fdb_add_del(emac, addr, prueth->default_vlan,
			  ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
			  ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
			  ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
			  ICSSG_FDB_ENTRY_BLOCK, false);
	vlan_id = is_vlan_dev(ndev) ? vlan_dev_vlan_id(ndev) : PRUETH_DFLT_VLAN_HSR;
	real_dev = is_vlan_dev(ndev) ? vlan_dev_real_dev(ndev) : ndev;

	if (is_hsr_master(real_dev)) {
		for (i = HSR_PT_SLAVE_A; i < HSR_PT_INTERLINK; i++) {
			emac = netdev_priv(hsr_get_port_ndev(real_dev, i));
			if (!emac)
				return -EINVAL;
			icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id,
						     false);
		}
	} else {
		emac = netdev_priv(real_dev);
		icssg_prueth_hsr_fdb_add_del(emac, addr, vlan_id, false);
	}

	return 0;
}
@@ -647,8 +681,14 @@ static int icssg_update_vlan_mcast(struct net_device *vdev, int vid,
				vdev->addr_len);
	netif_addr_unlock_bh(vdev);

	if (emac->prueth->is_hsr_offload_mode)
		__hw_addr_sync_dev(&emac->vlan_mcast_list[vid], vdev,
			   icssg_prueth_add_mcast, icssg_prueth_del_mcast);
				   icssg_prueth_hsr_add_mcast,
				   icssg_prueth_hsr_del_mcast);
	else
		__hw_addr_sync_dev(&emac->vlan_mcast_list[vid], vdev,
				   icssg_prueth_add_mcast,
				   icssg_prueth_del_mcast);

	return 0;
}
@@ -893,6 +933,11 @@ static void emac_ndo_set_rx_mode_work(struct work_struct *work)
	if (emac->prueth->is_hsr_offload_mode) {
		__dev_mc_sync(ndev, icssg_prueth_hsr_add_mcast,
			      icssg_prueth_hsr_del_mcast);
		if (rtnl_trylock()) {
			vlan_for_each(emac->prueth->hsr_dev,
				      icssg_update_vlan_mcast, emac);
			rtnl_unlock();
		}
	} else {
		__dev_mc_sync(ndev, icssg_prueth_add_mcast,
			      icssg_prueth_del_mcast);
@@ -1290,7 +1335,7 @@ static int prueth_netdevice_port_link(struct net_device *ndev,
		if (prueth->br_members & BIT(PRUETH_PORT_MII0) &&
		    prueth->br_members & BIT(PRUETH_PORT_MII1)) {
			prueth->is_switch_mode = true;
			prueth->default_vlan = 1;
			prueth->default_vlan = PRUETH_DFLT_VLAN_SW;
			emac->port_vlan = prueth->default_vlan;
			icssg_change_mode(prueth);
		}
@@ -1348,7 +1393,7 @@ static int prueth_hsr_port_link(struct net_device *ndev)
			      NETIF_PRUETH_HSR_OFFLOAD_FEATURES))
				return -EOPNOTSUPP;
			prueth->is_hsr_offload_mode = true;
			prueth->default_vlan = 1;
			prueth->default_vlan = PRUETH_DFLT_VLAN_HSR;
			emac0->port_vlan = prueth->default_vlan;
			emac1->port_vlan = prueth->default_vlan;
			icssg_change_mode(prueth);
+2 −0
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@
#define ICSS_CMD_ADD_MAC 0x8

/* VLAN Filtering Related MACROs */
#define PRUETH_DFLT_VLAN_HSR	1
#define PRUETH_DFLT_VLAN_SW	1
#define PRUETH_DFLT_VLAN_MAC	0
#define MAX_VLAN_ID		256