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: MD Danish Anwar <danishanwar@ti.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
MD Danish Anwar
2025-01-10 13:58:52 +05:30
committed by Paolo Abeni
parent 9c10dd8eed
commit 161087db66
2 changed files with 66 additions and 19 deletions

View File

@@ -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);
__hw_addr_sync_dev(&emac->vlan_mcast_list[vid], vdev,
icssg_prueth_add_mcast, icssg_prueth_del_mcast);
if (emac->prueth->is_hsr_offload_mode)
__hw_addr_sync_dev(&emac->vlan_mcast_list[vid], vdev,
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);

View File

@@ -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