Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net: ti: icssg-prueth: Add multicast filtering support

Add multicast filtering support for ICSSG Driver. Multicast addresses will
be updated by __dev_mc_sync() API. icssg_prueth_add_macst () and
icssg_prueth_del_mcast() will be sync and unsync APIs for the driver
respectively.

To add a mac_address for a port, driver needs to call icssg_fdb_add_del()
and pass the mac_address and BIT(port_id) to the API. The ICSSG firmware
will then configure the rules and allow filtering.

If a mac_address is added to port0 and the same mac_address needs to be
added for port1, driver needs to pass BIT(port0) | BIT(port1) to the
icssg_fdb_add_del() API. If driver just pass BIT(port1) then the entry for
port0 will be overwritten / lost. This is a design constraint on the
firmware side.

To overcome this in the driver, to add any mac_address for let's say portX
driver first checks if the same mac_address is already added for any other
port. If yes driver calls icssg_fdb_add_del() with BIT(portX) |
BIT(other_existing_port). If not, driver calls icssg_fdb_add_del() with
BIT(portX).

The same thing is applicable for deleting mac_addresses as well. This
logic is in icssg_prueth_add_mcast / icssg_prueth_del_mcast APIs.

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

MD Danish Anwar and committed by
David S. Miller
a9999732 cb6cf082

+34 -4
+34 -4
drivers/net/ethernet/ti/icssg/icssg_prueth.c
··· 439 439 .perout_enable = prueth_perout_enable, 440 440 }; 441 441 442 + static int icssg_prueth_add_mcast(struct net_device *ndev, const u8 *addr) 443 + { 444 + struct prueth_emac *emac = netdev_priv(ndev); 445 + int port_mask = BIT(emac->port_id); 446 + 447 + port_mask |= icssg_fdb_lookup(emac, addr, 0); 448 + icssg_fdb_add_del(emac, addr, 0, port_mask, true); 449 + icssg_vtbl_modify(emac, 0, port_mask, port_mask, true); 450 + 451 + return 0; 452 + } 453 + 454 + static int icssg_prueth_del_mcast(struct net_device *ndev, const u8 *addr) 455 + { 456 + struct prueth_emac *emac = netdev_priv(ndev); 457 + int port_mask = BIT(emac->port_id); 458 + int other_port_mask; 459 + 460 + other_port_mask = port_mask ^ icssg_fdb_lookup(emac, addr, 0); 461 + 462 + icssg_fdb_add_del(emac, addr, 0, port_mask, false); 463 + icssg_vtbl_modify(emac, 0, port_mask, port_mask, false); 464 + 465 + if (other_port_mask) { 466 + icssg_fdb_add_del(emac, addr, 0, other_port_mask, true); 467 + icssg_vtbl_modify(emac, 0, other_port_mask, other_port_mask, true); 468 + } 469 + 470 + return 0; 471 + } 472 + 442 473 /** 443 474 * emac_ndo_open - EMAC device open 444 475 * @ndev: network adapter device ··· 630 599 631 600 icssg_class_disable(prueth->miig_rt, prueth_emac_slice(emac)); 632 601 602 + __dev_mc_unsync(ndev, icssg_prueth_del_mcast); 603 + 633 604 atomic_set(&emac->tdown_cnt, emac->tx_ch_num); 634 605 /* ensure new tdown_cnt value is visible */ 635 606 smp_mb__after_atomic(); ··· 708 675 return; 709 676 } 710 677 711 - if (!netdev_mc_empty(ndev)) { 712 - emac_set_port_state(emac, ICSSG_EMAC_PORT_MC_FLOODING_ENABLE); 713 - return; 714 - } 678 + __dev_mc_sync(ndev, icssg_prueth_add_mcast, icssg_prueth_del_mcast); 715 679 } 716 680 717 681 /**