Skip to content

Commit

Permalink
net: ti: icssg-prueth: Add Support for Multicast filtering with VLAN …
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
MD Danish Anwar authored and Paolo Abeni committed Jan 14, 2025
1 parent 9c10dd8 commit 161087d
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 19 deletions.
83 changes: 64 additions & 19 deletions drivers/net/ethernet/ti/icssg/icssg_prueth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/ethernet/ti/icssg/icssg_prueth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 161087d

Please sign in to comment.