]> www.infradead.org Git - users/hch/misc.git/commitdiff
net: ti: icssg-prueth: Add Support for Multicast filtering with VLAN in HSR mode
authorMD Danish Anwar <danishanwar@ti.com>
Fri, 10 Jan 2025 08:28:52 +0000 (13:58 +0530)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 14 Jan 2025 11:17:27 +0000 (12:17 +0100)
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>
drivers/net/ethernet/ti/icssg/icssg_prueth.c
drivers/net/ethernet/ti/icssg/icssg_prueth.h

index b2d0d7b7b6d99e137a4d628f4ad8ab5f97ade99c..00ed978605478443e0e48e3f173586371e2aa1c7 100644 (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);
index c8f7a22cb253823e3574e99a8f570dbc3dac7b1a..329b46e9ee5300f533c42fdf8932c0d2f2340bb8 100644 (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