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.

Merge branch 'rzn1-a5psw-vlan-port_bridge_flags'

Alexis Lothoré says:

====================
net: dsa: rzn1-a5psw: add support for vlan and .port_bridge_flags

this series enables vlan support in Renesas RZN1 internal ethernet switch,
and is a follow up to the work initiated by Clement Leger a few months ago,
who handed me over the topic.
This new revision aims to iron the last few points raised by Vladimir to
ensure that the driver is in line with switch drivers expectations, and is
based on the lengthy discussion in [1] (thanks Vladimir for the valuable
explanations)

[1] https://lore.kernel.org/netdev/20230314163651.242259-1-clement.leger@bootlin.com/

----
V5:
- ensure that flooding can be enabled only if port belongs to a bridge
- enable learning in a5psw_port_stp_state_set() only if port has learning
enabled
- toggle vlan tagging on vlan filtering in
- removed reviewed-by on second patch since its modified

RESEND V4:
- Resent due to net-next being closed

V4:
- Fix missing CPU port bit in a5psw->bridged_ports
- Use unsigned int for vlan_res_id parameters
- Rename a5psw_get_vlan_res_entry() to a5psw_new_vlan_res_entry()
- In a5psw_port_vlan_add(), return -ENOSPC when no VLAN entry is found
- In a5psw_port_vlan_filtering(), compute "val" from "mask"

V3:
- Target net-next tree and correct version...

V2:
- Fixed a few formatting errors
- Add .port_bridge_flags implementation
====================

Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

+237 -11
+232 -8
drivers/net/dsa/rzn1_a5psw.c
··· 331 331 A5PSW_MCAST_DEF_MASK}; 332 332 int i; 333 333 334 - if (set) 335 - a5psw->bridged_ports |= BIT(port); 336 - else 337 - a5psw->bridged_ports &= ~BIT(port); 338 - 339 334 for (i = 0; i < ARRAY_SIZE(offsets); i++) 340 - a5psw_reg_writel(a5psw, offsets[i], a5psw->bridged_ports); 335 + a5psw_reg_rmw(a5psw, offsets[i], BIT(port), 336 + set ? BIT(port) : 0); 341 337 } 342 338 343 339 static void a5psw_port_set_standalone(struct a5psw *a5psw, int port, ··· 361 365 a5psw->br_dev = bridge.dev; 362 366 a5psw_port_set_standalone(a5psw, port, false); 363 367 368 + a5psw->bridged_ports |= BIT(port); 369 + 364 370 return 0; 365 371 } 366 372 ··· 371 373 { 372 374 struct a5psw *a5psw = ds->priv; 373 375 376 + a5psw->bridged_ports &= ~BIT(port); 377 + 374 378 a5psw_port_set_standalone(a5psw, port, true); 375 379 376 380 /* No more ports bridged */ ··· 380 380 a5psw->br_dev = NULL; 381 381 } 382 382 383 + static int a5psw_port_pre_bridge_flags(struct dsa_switch *ds, int port, 384 + struct switchdev_brport_flags flags, 385 + struct netlink_ext_ack *extack) 386 + { 387 + if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | 388 + BR_BCAST_FLOOD)) 389 + return -EINVAL; 390 + 391 + return 0; 392 + } 393 + 394 + static int 395 + a5psw_port_bridge_flags(struct dsa_switch *ds, int port, 396 + struct switchdev_brport_flags flags, 397 + struct netlink_ext_ack *extack) 398 + { 399 + struct a5psw *a5psw = ds->priv; 400 + u32 val; 401 + 402 + /* If a port is set as standalone, we do not want to be able to 403 + * configure flooding nor learning which would result in joining the 404 + * unique bridge. This can happen when a port leaves the bridge, in 405 + * which case the DSA core will try to "clear" all flags for the 406 + * standalone port (ie enable flooding, disable learning). In that case 407 + * do not fail but do not apply the flags. 408 + */ 409 + if (!(a5psw->bridged_ports & BIT(port))) 410 + return 0; 411 + 412 + if (flags.mask & BR_LEARNING) { 413 + val = flags.val & BR_LEARNING ? 0 : A5PSW_INPUT_LEARN_DIS(port); 414 + a5psw_reg_rmw(a5psw, A5PSW_INPUT_LEARN, 415 + A5PSW_INPUT_LEARN_DIS(port), val); 416 + } 417 + 418 + if (flags.mask & BR_FLOOD) { 419 + val = flags.val & BR_FLOOD ? BIT(port) : 0; 420 + a5psw_reg_rmw(a5psw, A5PSW_UCAST_DEF_MASK, BIT(port), val); 421 + } 422 + 423 + if (flags.mask & BR_MCAST_FLOOD) { 424 + val = flags.val & BR_MCAST_FLOOD ? BIT(port) : 0; 425 + a5psw_reg_rmw(a5psw, A5PSW_MCAST_DEF_MASK, BIT(port), val); 426 + } 427 + 428 + if (flags.mask & BR_BCAST_FLOOD) { 429 + val = flags.val & BR_BCAST_FLOOD ? BIT(port) : 0; 430 + a5psw_reg_rmw(a5psw, A5PSW_BCAST_DEF_MASK, BIT(port), val); 431 + } 432 + 433 + return 0; 434 + } 435 + 383 436 static void a5psw_port_stp_state_set(struct dsa_switch *ds, int port, u8 state) 384 437 { 385 438 bool learning_enabled, rx_enabled, tx_enabled; 439 + struct dsa_port *dp = dsa_to_port(ds, port); 386 440 struct a5psw *a5psw = ds->priv; 387 441 388 442 switch (state) { ··· 450 396 case BR_STATE_LEARNING: 451 397 rx_enabled = false; 452 398 tx_enabled = false; 453 - learning_enabled = true; 399 + learning_enabled = dp->learning; 454 400 break; 455 401 case BR_STATE_FORWARDING: 456 402 rx_enabled = true; 457 403 tx_enabled = true; 458 - learning_enabled = true; 404 + learning_enabled = dp->learning; 459 405 break; 460 406 default: 461 407 dev_err(ds->dev, "invalid STP state: %d\n", state); ··· 639 585 return ret; 640 586 } 641 587 588 + static int a5psw_port_vlan_filtering(struct dsa_switch *ds, int port, 589 + bool vlan_filtering, 590 + struct netlink_ext_ack *extack) 591 + { 592 + u32 mask = BIT(port + A5PSW_VLAN_VERI_SHIFT) | 593 + BIT(port + A5PSW_VLAN_DISC_SHIFT); 594 + u32 val = vlan_filtering ? mask : 0; 595 + struct a5psw *a5psw = ds->priv; 596 + 597 + /* Disable/enable vlan tagging */ 598 + a5psw_reg_rmw(a5psw, A5PSW_VLAN_IN_MODE_ENA, BIT(port), 599 + vlan_filtering ? BIT(port) : 0); 600 + 601 + /* Disable/enable vlan input filtering */ 602 + a5psw_reg_rmw(a5psw, A5PSW_VLAN_VERIFY, mask, val); 603 + 604 + return 0; 605 + } 606 + 607 + static int a5psw_find_vlan_entry(struct a5psw *a5psw, u16 vid) 608 + { 609 + u32 vlan_res; 610 + int i; 611 + 612 + /* Find vlan for this port */ 613 + for (i = 0; i < A5PSW_VLAN_COUNT; i++) { 614 + vlan_res = a5psw_reg_readl(a5psw, A5PSW_VLAN_RES(i)); 615 + if (FIELD_GET(A5PSW_VLAN_RES_VLANID, vlan_res) == vid) 616 + return i; 617 + } 618 + 619 + return -1; 620 + } 621 + 622 + static int a5psw_new_vlan_res_entry(struct a5psw *a5psw, u16 newvid) 623 + { 624 + u32 vlan_res; 625 + int i; 626 + 627 + /* Find a free VLAN entry */ 628 + for (i = 0; i < A5PSW_VLAN_COUNT; i++) { 629 + vlan_res = a5psw_reg_readl(a5psw, A5PSW_VLAN_RES(i)); 630 + if (!(FIELD_GET(A5PSW_VLAN_RES_PORTMASK, vlan_res))) { 631 + vlan_res = FIELD_PREP(A5PSW_VLAN_RES_VLANID, newvid); 632 + a5psw_reg_writel(a5psw, A5PSW_VLAN_RES(i), vlan_res); 633 + return i; 634 + } 635 + } 636 + 637 + return -1; 638 + } 639 + 640 + static void a5psw_port_vlan_tagged_cfg(struct a5psw *a5psw, 641 + unsigned int vlan_res_id, int port, 642 + bool set) 643 + { 644 + u32 mask = A5PSW_VLAN_RES_WR_PORTMASK | A5PSW_VLAN_RES_RD_TAGMASK | 645 + BIT(port); 646 + u32 vlan_res_off = A5PSW_VLAN_RES(vlan_res_id); 647 + u32 val = A5PSW_VLAN_RES_WR_TAGMASK, reg; 648 + 649 + if (set) 650 + val |= BIT(port); 651 + 652 + /* Toggle tag mask read */ 653 + a5psw_reg_writel(a5psw, vlan_res_off, A5PSW_VLAN_RES_RD_TAGMASK); 654 + reg = a5psw_reg_readl(a5psw, vlan_res_off); 655 + a5psw_reg_writel(a5psw, vlan_res_off, A5PSW_VLAN_RES_RD_TAGMASK); 656 + 657 + reg &= ~mask; 658 + reg |= val; 659 + a5psw_reg_writel(a5psw, vlan_res_off, reg); 660 + } 661 + 662 + static void a5psw_port_vlan_cfg(struct a5psw *a5psw, unsigned int vlan_res_id, 663 + int port, bool set) 664 + { 665 + u32 mask = A5PSW_VLAN_RES_WR_TAGMASK | BIT(port); 666 + u32 reg = A5PSW_VLAN_RES_WR_PORTMASK; 667 + 668 + if (set) 669 + reg |= BIT(port); 670 + 671 + a5psw_reg_rmw(a5psw, A5PSW_VLAN_RES(vlan_res_id), mask, reg); 672 + } 673 + 674 + static int a5psw_port_vlan_add(struct dsa_switch *ds, int port, 675 + const struct switchdev_obj_port_vlan *vlan, 676 + struct netlink_ext_ack *extack) 677 + { 678 + bool tagged = !(vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED); 679 + bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID; 680 + struct a5psw *a5psw = ds->priv; 681 + u16 vid = vlan->vid; 682 + int vlan_res_id; 683 + 684 + dev_dbg(a5psw->dev, "Add VLAN %d on port %d, %s, %s\n", 685 + vid, port, tagged ? "tagged" : "untagged", 686 + pvid ? "PVID" : "no PVID"); 687 + 688 + vlan_res_id = a5psw_find_vlan_entry(a5psw, vid); 689 + if (vlan_res_id < 0) { 690 + vlan_res_id = a5psw_new_vlan_res_entry(a5psw, vid); 691 + if (vlan_res_id < 0) 692 + return -ENOSPC; 693 + } 694 + 695 + a5psw_port_vlan_cfg(a5psw, vlan_res_id, port, true); 696 + if (tagged) 697 + a5psw_port_vlan_tagged_cfg(a5psw, vlan_res_id, port, true); 698 + 699 + /* Configure port to tag with corresponding VID, but do not enable it 700 + * yet: wait for vlan filtering to be enabled to enable vlan port 701 + * tagging 702 + */ 703 + if (pvid) 704 + a5psw_reg_writel(a5psw, A5PSW_SYSTEM_TAGINFO(port), vid); 705 + 706 + return 0; 707 + } 708 + 709 + static int a5psw_port_vlan_del(struct dsa_switch *ds, int port, 710 + const struct switchdev_obj_port_vlan *vlan) 711 + { 712 + struct a5psw *a5psw = ds->priv; 713 + u16 vid = vlan->vid; 714 + int vlan_res_id; 715 + 716 + dev_dbg(a5psw->dev, "Removing VLAN %d on port %d\n", vid, port); 717 + 718 + vlan_res_id = a5psw_find_vlan_entry(a5psw, vid); 719 + if (vlan_res_id < 0) 720 + return -EINVAL; 721 + 722 + a5psw_port_vlan_cfg(a5psw, vlan_res_id, port, false); 723 + a5psw_port_vlan_tagged_cfg(a5psw, vlan_res_id, port, false); 724 + 725 + return 0; 726 + } 727 + 642 728 static u64 a5psw_read_stat(struct a5psw *a5psw, u32 offset, int port) 643 729 { 644 730 u32 reg_lo, reg_hi; ··· 896 702 ctrl_stats->MACControlFramesReceived = stat; 897 703 } 898 704 705 + static void a5psw_vlan_setup(struct a5psw *a5psw, int port) 706 + { 707 + u32 reg; 708 + 709 + /* Enable TAG always mode for the port, this is actually controlled 710 + * by VLAN_IN_MODE_ENA field which will be used for PVID insertion 711 + */ 712 + reg = A5PSW_VLAN_IN_MODE_TAG_ALWAYS; 713 + reg <<= A5PSW_VLAN_IN_MODE_PORT_SHIFT(port); 714 + a5psw_reg_rmw(a5psw, A5PSW_VLAN_IN_MODE, A5PSW_VLAN_IN_MODE_PORT(port), 715 + reg); 716 + 717 + /* Set transparent mode for output frame manipulation, this will depend 718 + * on the VLAN_RES configuration mode 719 + */ 720 + reg = A5PSW_VLAN_OUT_MODE_TRANSPARENT; 721 + reg <<= A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port); 722 + a5psw_reg_rmw(a5psw, A5PSW_VLAN_OUT_MODE, 723 + A5PSW_VLAN_OUT_MODE_PORT(port), reg); 724 + } 725 + 899 726 static int a5psw_setup(struct dsa_switch *ds) 900 727 { 901 728 struct a5psw *a5psw = ds->priv; ··· 991 776 /* Enable standalone mode for user ports */ 992 777 if (dsa_port_is_user(dp)) 993 778 a5psw_port_set_standalone(a5psw, port, true); 779 + 780 + a5psw_vlan_setup(a5psw, port); 994 781 } 995 782 996 783 return 0; ··· 1018 801 .set_ageing_time = a5psw_set_ageing_time, 1019 802 .port_bridge_join = a5psw_port_bridge_join, 1020 803 .port_bridge_leave = a5psw_port_bridge_leave, 804 + .port_pre_bridge_flags = a5psw_port_pre_bridge_flags, 805 + .port_bridge_flags = a5psw_port_bridge_flags, 1021 806 .port_stp_state_set = a5psw_port_stp_state_set, 1022 807 .port_fast_age = a5psw_port_fast_age, 808 + .port_vlan_filtering = a5psw_port_vlan_filtering, 809 + .port_vlan_add = a5psw_port_vlan_add, 810 + .port_vlan_del = a5psw_port_vlan_del, 1023 811 .port_fdb_add = a5psw_port_fdb_add, 1024 812 .port_fdb_del = a5psw_port_fdb_del, 1025 813 .port_fdb_dump = a5psw_port_fdb_dump, ··· 1213 991 a5psw->base = devm_platform_ioremap_resource(pdev, 0); 1214 992 if (IS_ERR(a5psw->base)) 1215 993 return PTR_ERR(a5psw->base); 994 + 995 + a5psw->bridged_ports = BIT(A5PSW_CPU_PORT); 1216 996 1217 997 ret = a5psw_pcs_get(a5psw); 1218 998 if (ret)
+5 -3
drivers/net/dsa/rzn1_a5psw.h
··· 51 51 #define A5PSW_VLAN_IN_MODE_TAG_ALWAYS 0x2 52 52 53 53 #define A5PSW_VLAN_OUT_MODE 0x2C 54 - #define A5PSW_VLAN_OUT_MODE_PORT(port) (GENMASK(1, 0) << ((port) * 2)) 54 + #define A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port) ((port) * 2) 55 + #define A5PSW_VLAN_OUT_MODE_PORT(port) (GENMASK(1, 0) << \ 56 + A5PSW_VLAN_OUT_MODE_PORT_SHIFT(port)) 55 57 #define A5PSW_VLAN_OUT_MODE_DIS 0x0 56 58 #define A5PSW_VLAN_OUT_MODE_STRIP 0x1 57 59 #define A5PSW_VLAN_OUT_MODE_TAG_THROUGH 0x2 ··· 62 60 #define A5PSW_VLAN_IN_MODE_ENA 0x30 63 61 #define A5PSW_VLAN_TAG_ID 0x34 64 62 65 - #define A5PSW_SYSTEM_TAGINFO(port) (0x200 + A5PSW_PORT_OFFSET(port)) 63 + #define A5PSW_SYSTEM_TAGINFO(port) (0x200 + 4 * (port)) 66 64 67 65 #define A5PSW_AUTH_PORT(port) (0x240 + 4 * (port)) 68 66 #define A5PSW_AUTH_PORT_AUTHORIZED BIT(0) ··· 71 69 #define A5PSW_VLAN_RES_WR_PORTMASK BIT(30) 72 70 #define A5PSW_VLAN_RES_WR_TAGMASK BIT(29) 73 71 #define A5PSW_VLAN_RES_RD_TAGMASK BIT(28) 74 - #define A5PSW_VLAN_RES_ID GENMASK(16, 5) 72 + #define A5PSW_VLAN_RES_VLANID GENMASK(16, 5) 75 73 #define A5PSW_VLAN_RES_PORTMASK GENMASK(4, 0) 76 74 77 75 #define A5PSW_RXMATCH_CONFIG(port) (0x3e80 + 4 * (port))