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

net: sparx5: Allow mdb entries to both CPU and ports

Allow mdb entries to be forwarded to CPU and be switched at the same
time. Only remove entry when no port and the CPU isn't part of the group
anymore.

Signed-off-by: Casper Andersson <casper.casan@gmail.com>
Acked-by: Steen Hegelund <Steen.Hegelund@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Casper Andersson and committed by
David S. Miller
fbb89d02 c63c615e

+35 -20
+35 -20
drivers/net/ethernet/microchip/sparx5/sparx5_switchdev.c
··· 394 394 struct sparx5 *spx5 = port->sparx5; 395 395 u16 pgid_idx, vid; 396 396 u32 mact_entry; 397 + bool is_host; 397 398 int res, err; 398 399 399 - if (netif_is_bridge_master(v->obj.orig_dev)) { 400 - sparx5_mact_learn(spx5, PGID_CPU, v->addr, v->vid); 401 - return 0; 402 - } 400 + is_host = netif_is_bridge_master(v->obj.orig_dev); 403 401 404 402 /* When VLAN unaware the vlan value is not parsed and we receive vid 0. 405 403 * Fall back to bridge vid 1. ··· 414 416 415 417 /* MC_IDX starts after the port masks in the PGID table */ 416 418 pgid_idx += SPX5_PORTS; 417 - sparx5_pgid_update_mask(port, pgid_idx, true); 419 + 420 + if (is_host) 421 + spx5_rmw(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1), 422 + ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, spx5, 423 + ANA_AC_PGID_MISC_CFG(pgid_idx)); 424 + else 425 + sparx5_pgid_update_mask(port, pgid_idx, true); 426 + 418 427 } else { 419 428 err = sparx5_pgid_alloc_mcast(spx5, &pgid_idx); 420 429 if (err) { 421 430 netdev_warn(dev, "multicast pgid table full\n"); 422 431 return err; 423 432 } 424 - sparx5_pgid_update_mask(port, pgid_idx, true); 433 + 434 + if (is_host) 435 + spx5_rmw(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(1), 436 + ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, spx5, 437 + ANA_AC_PGID_MISC_CFG(pgid_idx)); 438 + else 439 + sparx5_pgid_update_mask(port, pgid_idx, true); 440 + 425 441 err = sparx5_mact_learn(spx5, pgid_idx, v->addr, vid); 442 + 426 443 if (err) { 427 444 netdev_warn(dev, "could not learn mac address %pM\n", v->addr); 445 + sparx5_pgid_free(spx5, pgid_idx); 428 446 sparx5_pgid_update_mask(port, pgid_idx, false); 429 447 return err; 430 448 } ··· 477 463 struct sparx5_port *port = netdev_priv(dev); 478 464 struct sparx5 *spx5 = port->sparx5; 479 465 u16 pgid_idx, vid; 480 - u32 mact_entry, res, pgid_entry[3]; 481 - int err; 482 - 483 - if (netif_is_bridge_master(v->obj.orig_dev)) { 484 - sparx5_mact_forget(spx5, v->addr, v->vid); 485 - return 0; 486 - } 466 + u32 mact_entry, res, pgid_entry[3], misc_cfg; 467 + bool host_ena; 487 468 488 469 if (!br_vlan_enabled(spx5->hw_bridge_dev)) 489 470 vid = 1; ··· 492 483 493 484 /* MC_IDX starts after the port masks in the PGID table */ 494 485 pgid_idx += SPX5_PORTS; 495 - sparx5_pgid_update_mask(port, pgid_idx, false); 486 + 487 + if (netif_is_bridge_master(v->obj.orig_dev)) 488 + spx5_rmw(ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_SET(0), 489 + ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA, spx5, 490 + ANA_AC_PGID_MISC_CFG(pgid_idx)); 491 + else 492 + sparx5_pgid_update_mask(port, pgid_idx, false); 493 + 494 + misc_cfg = spx5_rd(spx5, ANA_AC_PGID_MISC_CFG(pgid_idx)); 495 + host_ena = ANA_AC_PGID_MISC_CFG_PGID_CPU_COPY_ENA_GET(misc_cfg); 496 496 497 497 sparx5_pgid_read_mask(spx5, pgid_idx, pgid_entry); 498 - if (bitmap_empty((unsigned long *)pgid_entry, SPX5_PORTS)) { 499 - /* No ports are in MC group. Remove entry */ 500 - err = sparx5_mdb_del_entry(dev, spx5, v->addr, vid, pgid_idx); 501 - if (err) 502 - return err; 503 - } 498 + if (bitmap_empty((unsigned long *)pgid_entry, SPX5_PORTS) && !host_ena) 499 + /* No ports or CPU are in MC group. Remove entry */ 500 + return sparx5_mdb_del_entry(dev, spx5, v->addr, vid, pgid_idx); 504 501 } 505 502 506 503 return 0;