From patchwork Fri Feb 12 15:15:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382579 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 23684C433DB for ; Fri, 12 Feb 2021 15:17:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D415664DB1 for ; Fri, 12 Feb 2021 15:17:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231571AbhBLPQ4 (ORCPT ); Fri, 12 Feb 2021 10:16:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48046 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230047AbhBLPQv (ORCPT ); Fri, 12 Feb 2021 10:16:51 -0500 Received: from mail-ej1-x629.google.com (mail-ej1-x629.google.com [IPv6:2a00:1450:4864:20::629]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AEB6CC061756; Fri, 12 Feb 2021 07:16:11 -0800 (PST) Received: by mail-ej1-x629.google.com with SMTP id i8so16219593ejc.7; Fri, 12 Feb 2021 07:16:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=zlnjjFKVXOU0oDaJe+Eu8LG96OjY+3k7oZOIep+RtFc=; b=AIi+qIRyj6gQAHfCJw1wD5QNm2KIo3AWJW58DjXGAYsHdp3nWp6JoVnfd1cUvTMqNq C3GBfMMW7hJaYsvqhD7ft7yF9TsPci6nvI4V/+3qfPbHp25fuJjDJDnDhWd56LATg089 C1QKyJ9b/7GuMpv161MNp1szF+QWgJCqYbLOdyQ2QpGFfdl2kE7PxylqzVapcpxbUBe1 Ei05eyIF/bR0Cym981XcIabKgmJd1hn4z67Z1ra9ev62+nBmj8jIBdvQyBNoRrFGealn /Rdayvj6qls3zRiFOYswgwz/DHcICbq4bjnAdzKmzt/Jap3jGXOkW+/ihZBO69+gJ2eo X4+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=zlnjjFKVXOU0oDaJe+Eu8LG96OjY+3k7oZOIep+RtFc=; b=t7CyJk7YN9RxA6Lck0wdxI9ZIVY7EqeVosbkJSfPyaTQnMAOaFqbTO57C5gTrrHxzK Y95JP6gXnnCTr68d/9aXt6pg1mo8ZFZB2heQnAls5tQ0p6nT5FUXHK/WfFIZtfCKQWZZ Ho6HgC83bOw45mAtdSVKmAd2XXLookueGgY0MGi7XxyyREWKYm42KoZrZnCu907ZlIea 5ef66oexUjb5kx3yAjF9UDzlPJuiiKznXv70wdxxTgJhxeXYuOYSt5WZtKlpAtR8vrh0 ejPuEC1Uqey3evet16N1utqglIMimaCO/fV7/aevP8R2Xf+VPiyQ80hG5eg5q9+wMwxK jXpg== X-Gm-Message-State: AOAM532u1ID8mlRRvlJqsc7TNgt7xquTVnEkkNALwZO25hV170TckGqf xg+o/SBKeljJ39yLz/lwAx8= X-Google-Smtp-Source: ABdhPJxeCyxi9KPbcyN3yxNJUfpgpxfqZIf4SjJr31ziOyajmsidlG4SisiFvs2XHeADyKmNgalz4A== X-Received: by 2002:a17:906:8159:: with SMTP id z25mr3527245ejw.270.1613142970463; Fri, 12 Feb 2021 07:16:10 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:10 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 01/10] net: switchdev: propagate extack to port attributes Date: Fri, 12 Feb 2021 17:15:51 +0200 Message-Id: <20210212151600.3357121-2-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean When a struct switchdev_attr is notified through switchdev, there is no way to report informational messages, unlike for struct switchdev_obj. Signed-off-by: Vladimir Oltean Reviewed-by: Ido Schimmel Reviewed-by: Florian Fainelli --- Changes in v5: Rebased on top of AM65 CPSW driver merge. Changes in v4: None. Changes in v3: None. Changes in v2: Patch is new. .../ethernet/marvell/prestera/prestera_switchdev.c | 3 ++- .../net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 3 ++- drivers/net/ethernet/mscc/ocelot_net.c | 3 ++- drivers/net/ethernet/ti/am65-cpsw-switchdev.c | 3 ++- drivers/net/ethernet/ti/cpsw_switchdev.c | 3 ++- include/net/switchdev.h | 6 ++++-- net/dsa/slave.c | 3 ++- net/switchdev/switchdev.c | 11 ++++++++--- 8 files changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c index 8c2b03151736..2c1619715a4b 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c @@ -695,7 +695,8 @@ static int prestera_port_attr_stp_state_set(struct prestera_port *port, } static int prestera_port_obj_attr_set(struct net_device *dev, - const struct switchdev_attr *attr) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) { struct prestera_port *port = netdev_priv(dev); int err = 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 20c4f3c2cf23..18e4f1cd5587 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -887,7 +887,8 @@ mlxsw_sp_port_attr_br_mrouter_set(struct mlxsw_sp_port *mlxsw_sp_port, } static int mlxsw_sp_port_attr_set(struct net_device *dev, - const struct switchdev_attr *attr) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) { struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev); int err; diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c index 8f12fa45b1b5..f9da4aa39444 100644 --- a/drivers/net/ethernet/mscc/ocelot_net.c +++ b/drivers/net/ethernet/mscc/ocelot_net.c @@ -1005,7 +1005,8 @@ static void ocelot_port_attr_mc_set(struct ocelot *ocelot, int port, bool mc) } static int ocelot_port_attr_set(struct net_device *dev, - const struct switchdev_attr *attr) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) { struct ocelot_port_private *priv = netdev_priv(dev); struct ocelot *ocelot = priv->port.ocelot; diff --git a/drivers/net/ethernet/ti/am65-cpsw-switchdev.c b/drivers/net/ethernet/ti/am65-cpsw-switchdev.c index 1067e7772dbf..314825acf0a0 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-switchdev.c +++ b/drivers/net/ethernet/ti/am65-cpsw-switchdev.c @@ -81,7 +81,8 @@ static int am65_cpsw_port_attr_br_flags_pre_set(struct net_device *netdev, } static int am65_cpsw_port_attr_set(struct net_device *ndev, - const struct switchdev_attr *attr) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) { struct am65_cpsw_port *port = am65_ndev_to_port(ndev); int ret; diff --git a/drivers/net/ethernet/ti/cpsw_switchdev.c b/drivers/net/ethernet/ti/cpsw_switchdev.c index 9967cf985728..13524cbaa8b6 100644 --- a/drivers/net/ethernet/ti/cpsw_switchdev.c +++ b/drivers/net/ethernet/ti/cpsw_switchdev.c @@ -83,7 +83,8 @@ static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev, } static int cpsw_port_attr_set(struct net_device *ndev, - const struct switchdev_attr *attr) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) { struct cpsw_priv *priv = netdev_priv(ndev); int ret; diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 6dcfc4c51a6e..9279d4245bab 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -281,7 +281,8 @@ int switchdev_handle_port_attr_set(struct net_device *dev, struct switchdev_notifier_port_attr_info *port_attr_info, bool (*check_cb)(const struct net_device *dev), int (*set_cb)(struct net_device *dev, - const struct switchdev_attr *attr)); + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack)); #else static inline void switchdev_deferred_process(void) @@ -372,7 +373,8 @@ switchdev_handle_port_attr_set(struct net_device *dev, struct switchdev_notifier_port_attr_info *port_attr_info, bool (*check_cb)(const struct net_device *dev), int (*set_cb)(struct net_device *dev, - const struct switchdev_attr *attr)) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack)) { return 0; } diff --git a/net/dsa/slave.c b/net/dsa/slave.c index a95e78d59740..be29008477d3 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -272,7 +272,8 @@ static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } static int dsa_slave_port_attr_set(struct net_device *dev, - const struct switchdev_attr *attr) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack) { struct dsa_port *dp = dsa_slave_to_port(dev); int ret; diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 94113ca29dcf..0b84f076591e 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -488,14 +488,18 @@ static int __switchdev_handle_port_attr_set(struct net_device *dev, struct switchdev_notifier_port_attr_info *port_attr_info, bool (*check_cb)(const struct net_device *dev), int (*set_cb)(struct net_device *dev, - const struct switchdev_attr *attr)) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack)) { + struct netlink_ext_ack *extack; struct net_device *lower_dev; struct list_head *iter; int err = -EOPNOTSUPP; + extack = switchdev_notifier_info_to_extack(&port_attr_info->info); + if (check_cb(dev)) { - err = set_cb(dev, port_attr_info->attr); + err = set_cb(dev, port_attr_info->attr, extack); if (err != -EOPNOTSUPP) port_attr_info->handled = true; return err; @@ -525,7 +529,8 @@ int switchdev_handle_port_attr_set(struct net_device *dev, struct switchdev_notifier_port_attr_info *port_attr_info, bool (*check_cb)(const struct net_device *dev), int (*set_cb)(struct net_device *dev, - const struct switchdev_attr *attr)) + const struct switchdev_attr *attr, + struct netlink_ext_ack *extack)) { int err; From patchwork Fri Feb 12 15:15:52 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382104 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 66D2DC433DB for ; Fri, 12 Feb 2021 15:17:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 13D3C64DB1 for ; Fri, 12 Feb 2021 15:17:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231587AbhBLPRA (ORCPT ); Fri, 12 Feb 2021 10:17:00 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48054 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231422AbhBLPQy (ORCPT ); Fri, 12 Feb 2021 10:16:54 -0500 Received: from mail-ej1-x630.google.com (mail-ej1-x630.google.com [IPv6:2a00:1450:4864:20::630]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2E4E3C0613D6; Fri, 12 Feb 2021 07:16:13 -0800 (PST) Received: by mail-ej1-x630.google.com with SMTP id z19so2995380eju.9; Fri, 12 Feb 2021 07:16:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=VKLSm6k3jPNeAszvbHQZ5QowrDxdUrXYZ8jPfbijTRo=; b=I/Nj9W2AT0IDSHVhkKm4AvrrFuIB7vP9GTj39e3vFUswX8Y0eOd/yO7MEGCabTyby2 52Mvsx3pzYv/uunX2v9JmyvR4Stz+cd2HAMECZT/mGPWQytrQnJimEPhg9aL3WICtPEC my09/Z1WG/lvbemAHHBB9i1NA4Np4e+AQlVBUIyCrQSZwHl+sSJ62XrWck7ucoVxq6oD cS2Lfh46ZftFs8+kxJ2lfo0aPuIKLzxbzzs58FP1UO5V8957cgX0jg5S/VLoiPZ13bXB J0YLYYAm0oIABwxdhUOA2LmdAFxR1UOJPJR6oWHslrZS1nvjF0Vo9HL2wFUX4T3ayV+I cDLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=VKLSm6k3jPNeAszvbHQZ5QowrDxdUrXYZ8jPfbijTRo=; b=k2vCN4jaZP8NfMUJrBj8hwzg0IpxbPbAdENoVep9C/ZrUVunVjAoR1a6086s83/BQE T9E01Y1aP6pRCXGCBshQIX5iQlEBF3m0Z6M3x7p2L+DssVzzCC8crA4YIitudFxFK1C1 JCjqYRf9II5sJycq8ArNygLVMXe+kMzkxnpFVgEdK7sCwl0IibU4rcXmI0d5T9hGxYj2 QUT7VPJmikF5fSCgVGCFB5WL6wHK9kzuhkcd4SNhjl4TU1EqQ3loDWxihZIHEa3DOlRt TGv4tP1t6KE1LeTbJxncfiHDnu2t1KeolGOCPzuZgXxPz8zEZwKBsPih/7BT/f5zrENM ehTQ== X-Gm-Message-State: AOAM530Rw5G749kiY/8LplGMavnLpNiyYZJIBsJKRQRVd9qGA3fq0zLt Oge2llp8OJ3NtCT3hnMdKJs= X-Google-Smtp-Source: ABdhPJxf/b6pENTG+Sv+Pp+maBaS3X8/VWk+TsdRNEnhtZpEeZe6fEYB3IeJZ/PMpqb60cyh3JnY8A== X-Received: by 2002:a17:906:fb9a:: with SMTP id lr26mr3581412ejb.474.1613142971907; Fri, 12 Feb 2021 07:16:11 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:11 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 02/10] net: bridge: offload all port flags at once in br_setport Date: Fri, 12 Feb 2021 17:15:52 +0200 Message-Id: <20210212151600.3357121-3-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean If for example this command: ip link set swp0 type bridge_slave flood off mcast_flood off learning off succeeded at configuring BR_FLOOD and BR_MCAST_FLOOD but not at BR_LEARNING, there would be no attempt to revert the partial state in any way. Arguably, if the user changes more than one flag through the same netlink command, this one _should_ be all or nothing, which means it should be passed through switchdev as all or nothing. Signed-off-by: Vladimir Oltean Acked-by: Nikolay Aleksandrov --- Changes in v5: None. Changes in v4: Leave br->lock alone completely. Changes in v3: Don't attempt to drop br->lock around br_switchdev_set_port_flag now, move that part to a later patch. Changes in v2: Patch is new. Changes in v2: Patch is new. net/bridge/br_netlink.c | 109 ++++++++++++-------------------------- net/bridge/br_switchdev.c | 6 ++- 2 files changed, 39 insertions(+), 76 deletions(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index bd3962da345a..bf469f824944 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -853,87 +853,58 @@ static int br_set_port_state(struct net_bridge_port *p, u8 state) } /* Set/clear or port flags based on attribute */ -static int br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[], - int attrtype, unsigned long mask) +static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[], + int attrtype, unsigned long mask) { - unsigned long flags; - int err; - if (!tb[attrtype]) - return 0; + return; if (nla_get_u8(tb[attrtype])) - flags = p->flags | mask; + p->flags |= mask; else - flags = p->flags & ~mask; - - err = br_switchdev_set_port_flag(p, flags, mask); - if (err) - return err; - - p->flags = flags; - return 0; + p->flags &= ~mask; } /* Process bridge protocol info on port */ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) { - unsigned long old_flags = p->flags; - bool br_vlan_tunnel_old = false; + unsigned long old_flags, changed_mask; + bool br_vlan_tunnel_old; int err; - err = br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, BR_MULTICAST_TO_UNICAST); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI); - if (err) - return err; - - br_vlan_tunnel_old = (p->flags & BR_VLAN_TUNNEL) ? true : false; - err = br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL); - if (err) + old_flags = p->flags; + br_vlan_tunnel_old = (old_flags & BR_VLAN_TUNNEL) ? true : false; + + br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE); + br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD); + br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, + BR_MULTICAST_FAST_LEAVE); + br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK); + br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING); + br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD); + br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD); + br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, + BR_MULTICAST_TO_UNICAST); + br_set_port_flag(p, tb, IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD); + br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP); + br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI); + br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL); + br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS, BR_NEIGH_SUPPRESS); + br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED); + + changed_mask = old_flags ^ p->flags; + + err = br_switchdev_set_port_flag(p, p->flags, changed_mask); + if (err) { + p->flags = old_flags; return err; + } if (br_vlan_tunnel_old && !(p->flags & BR_VLAN_TUNNEL)) nbp_vlan_tunnel_info_flush(p); + br_port_flags_change(p, changed_mask); + if (tb[IFLA_BRPORT_COST]) { err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST])); if (err) @@ -982,15 +953,6 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) p->group_fwd_mask = fwd_mask; } - err = br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS, - BR_NEIGH_SUPPRESS); - if (err) - return err; - - err = br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED); - if (err) - return err; - if (tb[IFLA_BRPORT_BACKUP_PORT]) { struct net_device *backup_dev = NULL; u32 backup_ifindex; @@ -1008,7 +970,6 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) return err; } - br_port_flags_change(p, old_flags ^ p->flags); return 0; } diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index a9c23ef83443..6a9db6aa5c04 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -65,16 +65,18 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, struct switchdev_attr attr = { .orig_dev = p->dev, .id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS, - .u.brport_flags = mask, }; struct switchdev_notifier_port_attr_info info = { .attr = &attr, }; int err; - if (mask & ~BR_PORT_FLAGS_HW_OFFLOAD) + mask &= BR_PORT_FLAGS_HW_OFFLOAD; + if (!mask) return 0; + attr.u.brport_flags = mask; + /* We run from atomic context here */ err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev, &info.info, NULL); From patchwork Fri Feb 12 15:15:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382578 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F3ED7C433E6 for ; Fri, 12 Feb 2021 15:17:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B01BF64DB2 for ; Fri, 12 Feb 2021 15:17:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231603AbhBLPRF (ORCPT ); Fri, 12 Feb 2021 10:17:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48060 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231532AbhBLPQz (ORCPT ); Fri, 12 Feb 2021 10:16:55 -0500 Received: from mail-ej1-x62c.google.com (mail-ej1-x62c.google.com [IPv6:2a00:1450:4864:20::62c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF48BC061786; Fri, 12 Feb 2021 07:16:14 -0800 (PST) Received: by mail-ej1-x62c.google.com with SMTP id jj19so16279799ejc.4; Fri, 12 Feb 2021 07:16:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=v4AqKvOUM91B1bpyqKK0tQChu7IxeMQFeQvvQB4mTI0=; b=iSsJn2yN+adrSEbbjnjvwhkMS9X7pbY9ogfwuyPLmNGMErCiQ9HDYpkZGkACZWeRWh xNrfJXoM/DYR3C9SbZOaQB5hVi2J2wfe/FXbacIElXKBEjFvnHGDeVfpxpqFF7lna+N2 Od3MdAXRoYrOOLK/Jt2ZrPBPCG23yBMz1LWUcG30Gr/AZmq90YMwTE/66tSht7nX/Pth k744RRhrRVx8L975dggkJnMHTqyJDdAhtYeVzws96S7rBS0LUIMIVTS3tk2U3r/lKuCV zXeTeFazhl/T80mchimyHbi6ZVPINkf+tIYS2hWXWqHu6zI+Mnc7HWX3a6K0prRDfAgN nQXQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=v4AqKvOUM91B1bpyqKK0tQChu7IxeMQFeQvvQB4mTI0=; b=D4tJOX3eRGxmxKzclMMN9jijsNGowJimURB72pGUJVRHqxnS1SmKLJDpg4lqkm5GxI sUIxxj81AJj0eBiZhI+9JxmoQ4jidHolfHSkAJOAkgsBB0VL0EE7HwHUzL+wBHnf2vT8 1CgO7aPqudQipMISevyLLd9r5/4aZM1Gwjtls4CMyKz9V4D/BuhAQDOMNk84peKJDJ8J f2tUr5/6kNTMkOUnSeDSZHLCIQHK5y/40idqpj+Apyw3bZXtMgdHjS4gHzUW/PMSL+rk dHMH6k8idS3EgT4xeU7XHGVUhjiOSzpn8i3VJNENhL8oWEY95X0dwTQO3B3+cFYuJGPk NKaQ== X-Gm-Message-State: AOAM530CXakBHc0mQkr3GF07nfd2bjwROi/FkCHHgJicEWiUlhx+zmgA lKWKP/7H340gyb4bxzn0Xw8= X-Google-Smtp-Source: ABdhPJzkNglZztUwJlj67b6IY0EIW/Xwc96L7DNYcMIYJl1hGTVfx+MlFEPdSW5VtVVGWUy2rWOp5A== X-Received: by 2002:a17:906:4897:: with SMTP id v23mr2530257ejq.21.1613142973352; Fri, 12 Feb 2021 07:16:13 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:12 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 03/10] net: bridge: don't print in br_switchdev_set_port_flag Date: Fri, 12 Feb 2021 17:15:53 +0200 Message-Id: <20210212151600.3357121-4-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean For the netlink interface, propagate errors through extack rather than simply printing them to the console. For the sysfs interface, we still print to the console, but at least that's one layer higher than in switchdev, which also allows us to silently ignore the offloading of flags if that is ever needed in the future. Signed-off-by: Vladimir Oltean --- Changes in v5: None. Changes in v4: - Adjust the commit message now that we aren't notifying initial and final port flags from the bridge any longer. Changes in v3: - Deal with the br_switchdev_set_port_flag call from sysfs too. Changes in v2: - br_set_port_flag now returns void, so no extack there. - don't overwrite extack in br_switchdev_set_port_flag if already populated. net/bridge/br_netlink.c | 9 +++++---- net/bridge/br_private.h | 6 ++++-- net/bridge/br_switchdev.c | 13 +++++++------ net/bridge/br_sysfs_if.c | 7 +++++-- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index bf469f824944..7b513c5d347f 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -866,7 +866,8 @@ static void br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[], } /* Process bridge protocol info on port */ -static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) +static int br_setport(struct net_bridge_port *p, struct nlattr *tb[], + struct netlink_ext_ack *extack) { unsigned long old_flags, changed_mask; bool br_vlan_tunnel_old; @@ -894,7 +895,7 @@ static int br_setport(struct net_bridge_port *p, struct nlattr *tb[]) changed_mask = old_flags ^ p->flags; - err = br_switchdev_set_port_flag(p, p->flags, changed_mask); + err = br_switchdev_set_port_flag(p, p->flags, changed_mask, extack); if (err) { p->flags = old_flags; return err; @@ -1007,7 +1008,7 @@ int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags, return err; spin_lock_bh(&p->br->lock); - err = br_setport(p, tb); + err = br_setport(p, tb, extack); spin_unlock_bh(&p->br->lock); } else { /* Binary compatibility with old RSTP */ @@ -1102,7 +1103,7 @@ static int br_port_slave_changelink(struct net_device *brdev, return 0; spin_lock_bh(&br->lock); - ret = br_setport(br_port_get_rtnl(dev), data); + ret = br_setport(br_port_get_rtnl(dev), data, extack); spin_unlock_bh(&br->lock); return ret; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index d242ba668e47..a1639d41188b 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -1575,7 +1575,8 @@ bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, const struct sk_buff *skb); int br_switchdev_set_port_flag(struct net_bridge_port *p, unsigned long flags, - unsigned long mask); + unsigned long mask, + struct netlink_ext_ack *extack); void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type); int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags, @@ -1605,7 +1606,8 @@ static inline bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, static inline int br_switchdev_set_port_flag(struct net_bridge_port *p, unsigned long flags, - unsigned long mask) + unsigned long mask, + struct netlink_ext_ack *extack) { return 0; } diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index 6a9db6aa5c04..bb21dd35ae85 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -60,7 +60,8 @@ bool nbp_switchdev_allowed_egress(const struct net_bridge_port *p, int br_switchdev_set_port_flag(struct net_bridge_port *p, unsigned long flags, - unsigned long mask) + unsigned long mask, + struct netlink_ext_ack *extack) { struct switchdev_attr attr = { .orig_dev = p->dev, @@ -79,14 +80,15 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, /* We run from atomic context here */ err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev, - &info.info, NULL); + &info.info, extack); err = notifier_to_errno(err); if (err == -EOPNOTSUPP) return 0; if (err) { - br_warn(p->br, "bridge flag offload is not supported %u(%s)\n", - (unsigned int)p->port_no, p->dev->name); + if (extack && !extack->_msg) + NL_SET_ERR_MSG_MOD(extack, + "bridge flag offload is not supported"); return -EOPNOTSUPP; } @@ -96,8 +98,7 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, err = switchdev_port_attr_set(p->dev, &attr); if (err) { - br_warn(p->br, "error setting offload flag on port %u(%s)\n", - (unsigned int)p->port_no, p->dev->name); + NL_SET_ERR_MSG_MOD(extack, "error setting offload flag on port"); return err; } diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 5aea9427ffe1..72e92376eef1 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -59,6 +59,7 @@ static BRPORT_ATTR(_name, 0644, \ static int store_flag(struct net_bridge_port *p, unsigned long v, unsigned long mask) { + struct netlink_ext_ack extack = {0}; unsigned long flags = p->flags; int err; @@ -68,9 +69,11 @@ static int store_flag(struct net_bridge_port *p, unsigned long v, flags &= ~mask; if (flags != p->flags) { - err = br_switchdev_set_port_flag(p, flags, mask); - if (err) + err = br_switchdev_set_port_flag(p, flags, mask, &extack); + if (err) { + netdev_err(p->dev, "%s\n", extack._msg); return err; + } p->flags = flags; br_port_flags_change(p, mask); From patchwork Fri Feb 12 15:15:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382103 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0FAFBC433E9 for ; Fri, 12 Feb 2021 15:17:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CB95860C41 for ; Fri, 12 Feb 2021 15:17:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230515AbhBLPRI (ORCPT ); Fri, 12 Feb 2021 10:17:08 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48068 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231567AbhBLPQ4 (ORCPT ); Fri, 12 Feb 2021 10:16:56 -0500 Received: from mail-ej1-x62b.google.com (mail-ej1-x62b.google.com [IPv6:2a00:1450:4864:20::62b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 203D4C061788; Fri, 12 Feb 2021 07:16:16 -0800 (PST) Received: by mail-ej1-x62b.google.com with SMTP id f14so16221791ejc.8; Fri, 12 Feb 2021 07:16:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3txk3xzuaJ+luXWZVWBUlXIhxgR9+690DPw6ux/lwb4=; b=SAmMq4yYxfpPC2vCJkMrc9KnpLTTPktTIn/W2GRELoK84+vCpMSng2nd/0KJ872EgL DUigC7Ex19jWXuHQdlrCjYQnqqXaTn32p4CEPo90PTz3oYOr23Hf8/H2yazHJ917p1OK PPiWvl3eIENuZhkpVXXlg0XEeQgXLERZvUOIndxSdnV0EdeDIXECxiTU4/v82bSwaE4N jUxaJnSiqa6VTnFZpZzSIjMx47xy+ZcAa3FdTpXyEVhuvWZCiKqAJLxBW82hmoiTqIai FRbSr2PeALPvhsuHbfUWzFNByVyQ9K5vjaaYxtRo1LjwwBBjq+ae+3kgXwaaQCtPwSGk Dmyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=3txk3xzuaJ+luXWZVWBUlXIhxgR9+690DPw6ux/lwb4=; b=Mf9VMkDC7UoIoXfTVuEB4MtdVOJDda8Bvh3rU9ojuPWwLtQwCVgOE2g1nq6DFw8drc ueSxhEtSyyriF98iySgoRawLgCWD+6MCtMb5zAKiieAkrj1zzwNzEb+L1OTfV+DOvuoZ B6WyCMK8gr8/JjB1Owj/8dxz/tgIz75yp8i7PxAkwbDEe7mhDGTk8pmOcFEAOAdC+m75 MNr53N5gu7S4er/wNmvY593AJ6zaJMLa73f9Ay3qPlAOnjKP6BN3xjBMYcMbSvCgDdgv sUtYqAfJiTphePkQy728EtC4lav2IiOt4mBlG3+kefVTHOLKOl5gMf//P6Tjg/5G7tfU uqJQ== X-Gm-Message-State: AOAM530vNkRBXOKDr2LJ3pav2/pNA9PPQ3ms4rENbHibP8nky1vA2zf0 hGXhrqMjnzf/HKP68btAOQg= X-Google-Smtp-Source: ABdhPJzkVczuOmaW3fpNoup+Al6snwdDJs3c7fOUYtx5bEaFBiZ4R5Q/CAwAKIcewHJ9t9fXp1huAA== X-Received: by 2002:a17:906:86cf:: with SMTP id j15mr3454069ejy.194.1613142974845; Fri, 12 Feb 2021 07:16:14 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:14 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 04/10] net: dsa: configure better brport flags when ports leave the bridge Date: Fri, 12 Feb 2021 17:15:54 +0200 Message-Id: <20210212151600.3357121-5-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean For a DSA switch port operating in standalone mode, address learning doesn't make much sense since that is a bridge function. In fact, address learning even breaks setups such as this one: +---------------------------------------------+ | | | +-------------------+ | | | br0 | send receive | | +--------+-+--------+ +--------+ +--------+ | | | | | | | | | | | | | swp0 | | swp1 | | swp2 | | swp3 | | | | | | | | | | | | +-+--------+-+--------+-+--------+-+--------+-+ | ^ | ^ | | | | | +-----------+ | | | +--------------------------------+ because if the switch has a single FDB (can offload a single bridge) then source address learning on swp3 can "steal" the source MAC address of swp2 from br0's FDB, because learning frames coming from swp2 will be done twice: first on the swp1 ingress port, second on the swp3 ingress port. So the hardware FDB will become out of sync with the software bridge, and when swp2 tries to send one more packet towards swp1, the ASIC will attempt to short-circuit the forwarding path and send it directly to swp3 (since that's the last port it learned that address on), which it obviously can't, because swp3 operates in standalone mode. So DSA drivers operating in standalone mode should still configure a list of bridge port flags even when they are standalone. Currently DSA attempts to call dsa_port_bridge_flags with 0, which disables egress flooding of unknown unicast and multicast, something which doesn't make much sense. For the switches that implement .port_egress_floods - b53 and mv88e6xxx, it probably doesn't matter too much either, since they can possibly inject traffic from the CPU into a standalone port, regardless of MAC DA, even if egress flooding is turned off for that port, but certainly not all DSA switches can do that - sja1105, for example, can't. So it makes sense to use a better common default there, such as "flood everything". It should also be noted that what DSA calls "dsa_port_bridge_flags()" is a degenerate name for just calling .port_egress_floods(), since nothing else is implemented - not learning, in particular. But disabling address learning, something that this driver is also coding up for, will be supported by individual drivers once .port_egress_floods is replaced with a more generic .port_bridge_flags. Previous attempts to code up this logic have been in the common bridge layer, but as pointed out by Ido Schimmel, there are corner cases that are missed when doing that: https://patchwork.kernel.org/project/netdevbpf/patch/20210209151936.97382-5-olteanv@gmail.com/ So, at least for now, let's leave DSA in charge of setting port flags before and after the bridge join and leave. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- Changes in v5: None. Changes in v4: None. Changes in v3: Patch is new, logically it was moved from the bridge layer to the DSA layer. net/dsa/port.c | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/net/dsa/port.c b/net/dsa/port.c index b93bda463026..1f877bf21bb4 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -122,6 +122,27 @@ void dsa_port_disable(struct dsa_port *dp) rtnl_unlock(); } +static void dsa_port_change_brport_flags(struct dsa_port *dp, + bool bridge_offload) +{ + unsigned long mask, flags; + int flag, err; + + mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; + if (bridge_offload) + flags = mask; + else + flags = mask & ~BR_LEARNING; + + for_each_set_bit(flag, &mask, 32) { + err = dsa_port_pre_bridge_flags(dp, BIT(flag)); + if (err) + continue; + + dsa_port_bridge_flags(dp, flags & BIT(flag)); + } +} + int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) { struct dsa_notifier_bridge_info info = { @@ -132,10 +153,10 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) }; int err; - /* Set the flooding mode before joining the port in the switch */ - err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD); - if (err) - return err; + /* Notify the port driver to set its configurable flags in a way that + * matches the initial settings of a bridge port. + */ + dsa_port_change_brport_flags(dp, true); /* Here the interface is already bridged. Reflect the current * configuration so that drivers can program their chips accordingly. @@ -146,7 +167,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) /* The bridging is rolled back on error */ if (err) { - dsa_port_bridge_flags(dp, 0); + dsa_port_change_brport_flags(dp, false); dp->bridge_dev = NULL; } @@ -172,8 +193,18 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) if (err) pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); - /* Port is leaving the bridge, disable flooding */ - dsa_port_bridge_flags(dp, 0); + /* Configure the port for standalone mode (no address learning, + * flood everything). + * The bridge only emits SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS events + * when the user requests it through netlink or sysfs, but not + * automatically at port join or leave, so we need to handle resetting + * the brport flags ourselves. But we even prefer it that way, because + * otherwise, some setups might never get the notification they need, + * for example, when a port leaves a LAG that offloads the bridge, + * it becomes standalone, but as far as the bridge is concerned, no + * port ever left. + */ + dsa_port_change_brport_flags(dp, false); /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional From patchwork Fri Feb 12 15:15:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382577 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 82856C4332D for ; Fri, 12 Feb 2021 15:18:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3A7EC64DB1 for ; Fri, 12 Feb 2021 15:18:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231727AbhBLPRu (ORCPT ); Fri, 12 Feb 2021 10:17:50 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48200 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230197AbhBLPRd (ORCPT ); Fri, 12 Feb 2021 10:17:33 -0500 Received: from mail-ed1-x530.google.com (mail-ed1-x530.google.com [IPv6:2a00:1450:4864:20::530]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE1DEC06178A; Fri, 12 Feb 2021 07:16:17 -0800 (PST) Received: by mail-ed1-x530.google.com with SMTP id v7so34063eds.10; Fri, 12 Feb 2021 07:16:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=ficNygvMQR2i/ynCstk4J2m6rytXns5Vj35F/uwG9iI=; b=AiE9sZINQia2D+iU4b35DSwYBvtNu5zvRLJdlImDQguYNbDlp8kSCO/RcQrXExFPEL GG+wMAauFLxTWrJVQ5gm95BXTxogPuHD+KuP7gAvDEWvDXx1HKAdGcFiZR4INwPTXCjN UUA3yusySmx7tdU/KeIL2wQEkbbbQMvI8Brh5uPMf40nM4uHRaecZpCq6BoV0+dOaKgV QZIrMZfoAAi3rPTjjkXiqcH6i4+YLeD4kRZvKkWt1ilsgH8Hdg0FxipXu0OajASiT7cD TpsTw3HYkGu6QQpKMUFGiDSYkBgV+qO5kCg7LheYbdVm/ez55Z9bV43t1/4hMGBxNt1K 0v2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=ficNygvMQR2i/ynCstk4J2m6rytXns5Vj35F/uwG9iI=; b=IAmMrXmrFoYUYhLot3PIgbfdutzjX5l53VgBKdB/Zz9kZ/hlg9aRJLvAkFIDpd5lXm zzraXXvQa67kimM3yQp17RWDV28k67/4dgbK1VfEPUo3WshAXn19qeGVo1UOiAPt6vjb 2NAaNNAPaA3hyvVbJinvWe73ph934jPeINgHbphHSs+mqRVl7ye2ljMD+21Aik26KY8g AjILs+9JHvVqkAIVzeDWrj6xJpZO04AywJ2U3n1sQ4REFB26l4WrRG4XCjgHz+RDNqLZ BMfxWO3RxAh53p9yXbob2877dzZFMTURUEC84/B6DvEx5kKgEKhNZ+IlSt6b9ZWWNacL Lj8w== X-Gm-Message-State: AOAM533zJLh5TrLmCQqBmwKHpeHsDDWrpT9Kv+I+n4EKMhyikkHtdE2z 5cFuJSVJz/4PrIvf4MoPEKg= X-Google-Smtp-Source: ABdhPJwuujPf5hXytnk6kPQoTSTcaFsFlFxsxStjrYKKciQXf4J2wfDmU6AFaHtG93l1+2gCn2fzrg== X-Received: by 2002:a05:6402:5207:: with SMTP id s7mr3703480edd.311.1613142976353; Fri, 12 Feb 2021 07:16:16 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:15 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 05/10] net: switchdev: pass flags and mask to both {PRE_, }BRIDGE_FLAGS attributes Date: Fri, 12 Feb 2021 17:15:55 +0200 Message-Id: <20210212151600.3357121-6-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean This switchdev attribute offers a counterproductive API for a driver writer, because although br_switchdev_set_port_flag gets passed a "flags" and a "mask", those are passed piecemeal to the driver, so while the PRE_BRIDGE_FLAGS listener knows what changed because it has the "mask", the BRIDGE_FLAGS listener doesn't, because it only has the final value. But certain drivers can offload only certain combinations of settings, like for example they cannot change unicast flooding independently of multicast flooding - they must be both on or both off. The way the information is passed to switchdev makes drivers not expressive enough, and unable to reject this request ahead of time, in the PRE_BRIDGE_FLAGS notifier, so they are forced to reject it during the deferred BRIDGE_FLAGS attribute, where the rejection is currently ignored. This patch also changes drivers to make use of the "mask" field for edge detection when possible. Signed-off-by: Vladimir Oltean --- Changes in v5: Rebased on top of AM65 CPSW driver. Changes in v4: Patch is new. .../marvell/prestera/prestera_switchdev.c | 23 +++++---- .../mellanox/mlxsw/spectrum_switchdev.c | 50 +++++++++++-------- drivers/net/ethernet/rocker/rocker_main.c | 10 ++-- drivers/net/ethernet/ti/am65-cpsw-switchdev.c | 24 +++++---- drivers/net/ethernet/ti/cpsw_switchdev.c | 24 +++++---- drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 34 ++++++++----- include/net/switchdev.h | 7 ++- net/bridge/br_switchdev.c | 6 +-- net/dsa/dsa_priv.h | 6 ++- net/dsa/port.c | 34 +++++++------ 10 files changed, 129 insertions(+), 89 deletions(-) diff --git a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c index 2c1619715a4b..49e052273f30 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_switchdev.c @@ -581,7 +581,7 @@ int prestera_bridge_port_event(struct net_device *dev, unsigned long event, static int prestera_port_attr_br_flags_set(struct prestera_port *port, struct net_device *dev, - unsigned long flags) + struct switchdev_brport_flags flags) { struct prestera_bridge_port *br_port; int err; @@ -590,15 +590,20 @@ static int prestera_port_attr_br_flags_set(struct prestera_port *port, if (!br_port) return 0; - err = prestera_hw_port_flood_set(port, flags & BR_FLOOD); - if (err) - return err; + if (flags.mask & BR_FLOOD) { + err = prestera_hw_port_flood_set(port, flags.val & BR_FLOOD); + if (err) + return err; + } - err = prestera_hw_port_learning_set(port, flags & BR_LEARNING); - if (err) - return err; + if (flags.mask & BR_LEARNING) { + err = prestera_hw_port_learning_set(port, + flags.val & BR_LEARNING); + if (err) + return err; + } - memcpy(&br_port->flags, &flags, sizeof(flags)); + memcpy(&br_port->flags, &flags.val, sizeof(flags.val)); return 0; } @@ -707,7 +712,7 @@ static int prestera_port_obj_attr_set(struct net_device *dev, attr->u.stp_state); break; case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: - if (attr->u.brport_flags & + if (attr->u.brport_flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD)) err = -EINVAL; break; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 18e4f1cd5587..23b7e8d6386b 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -653,11 +653,11 @@ mlxsw_sp_bridge_port_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, return err; } -static int mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port - *mlxsw_sp_port, - unsigned long brport_flags) +static int +mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, + struct switchdev_brport_flags flags) { - if (brport_flags & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD)) + if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD)) return -EINVAL; return 0; @@ -665,7 +665,7 @@ static int mlxsw_sp_port_attr_br_pre_flags_set(struct mlxsw_sp_port static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, struct net_device *orig_dev, - unsigned long brport_flags) + struct switchdev_brport_flags flags) { struct mlxsw_sp_bridge_port *bridge_port; int err; @@ -675,29 +675,37 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, if (!bridge_port) return 0; - err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, - MLXSW_SP_FLOOD_TYPE_UC, - brport_flags & BR_FLOOD); - if (err) - return err; + if (flags.mask & BR_FLOOD) { + err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, + bridge_port, + MLXSW_SP_FLOOD_TYPE_UC, + flags.val & BR_FLOOD); + if (err) + return err; + } - err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port, bridge_port, - brport_flags & BR_LEARNING); - if (err) - return err; + if (flags.mask & BR_LEARNING) { + err = mlxsw_sp_bridge_port_learning_set(mlxsw_sp_port, + bridge_port, + flags.val & BR_LEARNING); + if (err) + return err; + } if (bridge_port->bridge_device->multicast_enabled) goto out; - err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, - MLXSW_SP_FLOOD_TYPE_MC, - brport_flags & - BR_MCAST_FLOOD); - if (err) - return err; + if (flags.mask & BR_MCAST_FLOOD) { + err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, + bridge_port, + MLXSW_SP_FLOOD_TYPE_MC, + flags.val & BR_MCAST_FLOOD); + if (err) + return err; + } out: - memcpy(&bridge_port->flags, &brport_flags, sizeof(brport_flags)); + memcpy(&bridge_port->flags, &flags.val, sizeof(flags.val)); return 0; } diff --git a/drivers/net/ethernet/rocker/rocker_main.c b/drivers/net/ethernet/rocker/rocker_main.c index 740a715c49c6..3473d296b2e2 100644 --- a/drivers/net/ethernet/rocker/rocker_main.c +++ b/drivers/net/ethernet/rocker/rocker_main.c @@ -1576,7 +1576,7 @@ rocker_world_port_attr_bridge_flags_support_get(const struct rocker_port * static int rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port, - unsigned long brport_flags) + struct switchdev_brport_flags flags) { struct rocker_world_ops *wops = rocker_port->rocker->wops; unsigned long brport_flags_s; @@ -1590,7 +1590,7 @@ rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port, if (err) return err; - if (brport_flags & ~brport_flags_s) + if (flags.mask & ~brport_flags_s) return -EINVAL; return 0; @@ -1598,14 +1598,14 @@ rocker_world_port_attr_pre_bridge_flags_set(struct rocker_port *rocker_port, static int rocker_world_port_attr_bridge_flags_set(struct rocker_port *rocker_port, - unsigned long brport_flags) + struct switchdev_brport_flags flags) { struct rocker_world_ops *wops = rocker_port->rocker->wops; if (!wops->port_attr_bridge_flags_set) return -EOPNOTSUPP; - return wops->port_attr_bridge_flags_set(rocker_port, brport_flags); + return wops->port_attr_bridge_flags_set(rocker_port, flags.val); } static int @@ -2058,7 +2058,7 @@ static int rocker_port_attr_set(struct net_device *dev, break; case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: err = rocker_world_port_attr_pre_bridge_flags_set(rocker_port, - attr->u.brport_flags); + attr->u.brport_flags); break; case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: err = rocker_world_port_attr_bridge_flags_set(rocker_port, diff --git a/drivers/net/ethernet/ti/am65-cpsw-switchdev.c b/drivers/net/ethernet/ti/am65-cpsw-switchdev.c index 314825acf0a0..d93ffd8a08b0 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-switchdev.c +++ b/drivers/net/ethernet/ti/am65-cpsw-switchdev.c @@ -55,26 +55,30 @@ static int am65_cpsw_port_stp_state_set(struct am65_cpsw_port *port, u8 state) static int am65_cpsw_port_attr_br_flags_set(struct am65_cpsw_port *port, struct net_device *orig_dev, - unsigned long brport_flags) + struct switchdev_brport_flags flags) { struct am65_cpsw_common *cpsw = port->common; - bool unreg_mcast_add = false; - if (brport_flags & BR_MCAST_FLOOD) - unreg_mcast_add = true; - netdev_dbg(port->ndev, "BR_MCAST_FLOOD: %d port %u\n", - unreg_mcast_add, port->port_id); + if (flags.mask & BR_MCAST_FLOOD) { + bool unreg_mcast_add = false; - cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(port->port_id), - unreg_mcast_add); + if (flags.val & BR_MCAST_FLOOD) + unreg_mcast_add = true; + + netdev_dbg(port->ndev, "BR_MCAST_FLOOD: %d port %u\n", + unreg_mcast_add, port->port_id); + + cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(port->port_id), + unreg_mcast_add); + } return 0; } static int am65_cpsw_port_attr_br_flags_pre_set(struct net_device *netdev, - unsigned long flags) + struct switchdev_brport_flags flags) { - if (flags & ~(BR_LEARNING | BR_MCAST_FLOOD)) + if (flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD)) return -EINVAL; return 0; diff --git a/drivers/net/ethernet/ti/cpsw_switchdev.c b/drivers/net/ethernet/ti/cpsw_switchdev.c index 13524cbaa8b6..a72bb570756f 100644 --- a/drivers/net/ethernet/ti/cpsw_switchdev.c +++ b/drivers/net/ethernet/ti/cpsw_switchdev.c @@ -57,26 +57,30 @@ static int cpsw_port_stp_state_set(struct cpsw_priv *priv, u8 state) static int cpsw_port_attr_br_flags_set(struct cpsw_priv *priv, struct net_device *orig_dev, - unsigned long brport_flags) + struct switchdev_brport_flags flags) { struct cpsw_common *cpsw = priv->cpsw; - bool unreg_mcast_add = false; - if (brport_flags & BR_MCAST_FLOOD) - unreg_mcast_add = true; - dev_dbg(priv->dev, "BR_MCAST_FLOOD: %d port %u\n", - unreg_mcast_add, priv->emac_port); + if (flags.mask & BR_MCAST_FLOOD) { + bool unreg_mcast_add = false; - cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(priv->emac_port), - unreg_mcast_add); + if (flags.val & BR_MCAST_FLOOD) + unreg_mcast_add = true; + + dev_dbg(priv->dev, "BR_MCAST_FLOOD: %d port %u\n", + unreg_mcast_add, priv->emac_port); + + cpsw_ale_set_unreg_mcast(cpsw->ale, BIT(priv->emac_port), + unreg_mcast_add); + } return 0; } static int cpsw_port_attr_br_flags_pre_set(struct net_device *netdev, - unsigned long flags) + struct switchdev_brport_flags flags) { - if (flags & ~(BR_LEARNING | BR_MCAST_FLOOD)) + if (flags.mask & ~(BR_LEARNING | BR_MCAST_FLOOD)) return -EINVAL; return 0; diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c index ca3d07fe7f58..703055e063ff 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c @@ -908,31 +908,39 @@ static int dpaa2_switch_port_attr_stp_state_set(struct net_device *netdev, return dpaa2_switch_port_set_stp_state(port_priv, state); } -static int dpaa2_switch_port_attr_br_flags_pre_set(struct net_device *netdev, - unsigned long flags) +static int +dpaa2_switch_port_attr_br_flags_pre_set(struct net_device *netdev, + struct switchdev_brport_flags flags) { - if (flags & ~(BR_LEARNING | BR_FLOOD)) + if (flags.mask & ~(BR_LEARNING | BR_FLOOD)) return -EINVAL; return 0; } -static int dpaa2_switch_port_attr_br_flags_set(struct net_device *netdev, - unsigned long flags) +static int +dpaa2_switch_port_attr_br_flags_set(struct net_device *netdev, + struct switchdev_brport_flags flags) { struct ethsw_port_priv *port_priv = netdev_priv(netdev); int err = 0; - /* Learning is enabled per switch */ - err = dpaa2_switch_set_learning(port_priv->ethsw_data, - !!(flags & BR_LEARNING)); - if (err) - goto exit; + if (flags.mask & BR_LEARNING) { + /* Learning is enabled per switch */ + err = dpaa2_switch_set_learning(port_priv->ethsw_data, + !!(flags.val & BR_LEARNING)); + if (err) + return err; + } - err = dpaa2_switch_port_set_flood(port_priv, !!(flags & BR_FLOOD)); + if (flags.mask & BR_FLOOD) { + err = dpaa2_switch_port_set_flood(port_priv, + !!(flags.val & BR_FLOOD)); + if (err) + return err; + } -exit: - return err; + return 0; } static int dpaa2_switch_port_attr_set(struct net_device *netdev, diff --git a/include/net/switchdev.h b/include/net/switchdev.h index 9279d4245bab..25d9e4570934 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -32,6 +32,11 @@ enum switchdev_attr_id { #endif }; +struct switchdev_brport_flags { + unsigned long val; + unsigned long mask; +}; + struct switchdev_attr { struct net_device *orig_dev; enum switchdev_attr_id id; @@ -40,7 +45,7 @@ struct switchdev_attr { void (*complete)(struct net_device *dev, int err, void *priv); union { u8 stp_state; /* PORT_STP_STATE */ - unsigned long brport_flags; /* PORT_{PRE}_BRIDGE_FLAGS */ + struct switchdev_brport_flags brport_flags; /* PORT_BRIDGE_FLAGS */ bool mrouter; /* PORT_MROUTER */ clock_t ageing_time; /* BRIDGE_AGEING_TIME */ bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */ diff --git a/net/bridge/br_switchdev.c b/net/bridge/br_switchdev.c index bb21dd35ae85..184cf4c8b06d 100644 --- a/net/bridge/br_switchdev.c +++ b/net/bridge/br_switchdev.c @@ -65,7 +65,6 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, { struct switchdev_attr attr = { .orig_dev = p->dev, - .id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS, }; struct switchdev_notifier_port_attr_info info = { .attr = &attr, @@ -76,7 +75,9 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, if (!mask) return 0; - attr.u.brport_flags = mask; + attr.id = SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS; + attr.u.brport_flags.val = flags; + attr.u.brport_flags.mask = mask; /* We run from atomic context here */ err = call_switchdev_notifiers(SWITCHDEV_PORT_ATTR_SET, p->dev, @@ -94,7 +95,6 @@ int br_switchdev_set_port_flag(struct net_bridge_port *p, attr.id = SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS; attr.flags = SWITCHDEV_F_DEFER; - attr.u.brport_flags = flags; err = switchdev_port_attr_set(p->dev, &attr); if (err) { diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 7060f128386b..bc835f3de2be 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -183,8 +183,10 @@ int dsa_port_mdb_add(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb); int dsa_port_mdb_del(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb); -int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags); -int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags); +int dsa_port_pre_bridge_flags(const struct dsa_port *dp, + struct switchdev_brport_flags flags); +int dsa_port_bridge_flags(const struct dsa_port *dp, + struct switchdev_brport_flags flags); int dsa_port_mrouter(struct dsa_port *dp, bool mrouter); int dsa_port_vlan_add(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan); diff --git a/net/dsa/port.c b/net/dsa/port.c index 1f877bf21bb4..368064dfd93e 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -125,21 +125,22 @@ void dsa_port_disable(struct dsa_port *dp) static void dsa_port_change_brport_flags(struct dsa_port *dp, bool bridge_offload) { - unsigned long mask, flags; - int flag, err; + struct switchdev_brport_flags flags; + int flag; - mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; + flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; if (bridge_offload) - flags = mask; + flags.val = flags.mask; else - flags = mask & ~BR_LEARNING; + flags.val = flags.mask & ~BR_LEARNING; - for_each_set_bit(flag, &mask, 32) { - err = dsa_port_pre_bridge_flags(dp, BIT(flag)); - if (err) - continue; + for_each_set_bit(flag, &flags.mask, 32) { + struct switchdev_brport_flags tmp; + + tmp.val = flags.val & BIT(flag); + tmp.mask = BIT(flag); - dsa_port_bridge_flags(dp, flags & BIT(flag)); + dsa_port_bridge_flags(dp, tmp); } } @@ -423,26 +424,29 @@ int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock) return 0; } -int dsa_port_pre_bridge_flags(const struct dsa_port *dp, unsigned long flags) +int dsa_port_pre_bridge_flags(const struct dsa_port *dp, + struct switchdev_brport_flags flags) { struct dsa_switch *ds = dp->ds; if (!ds->ops->port_egress_floods || - (flags & ~(BR_FLOOD | BR_MCAST_FLOOD))) + (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD))) return -EINVAL; return 0; } -int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags) +int dsa_port_bridge_flags(const struct dsa_port *dp, + struct switchdev_brport_flags flags) { struct dsa_switch *ds = dp->ds; int port = dp->index; int err = 0; if (ds->ops->port_egress_floods) - err = ds->ops->port_egress_floods(ds, port, flags & BR_FLOOD, - flags & BR_MCAST_FLOOD); + err = ds->ops->port_egress_floods(ds, port, + flags.val & BR_FLOOD, + flags.val & BR_MCAST_FLOOD); return err; } From patchwork Fri Feb 12 15:15:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382576 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5D5ECC4332B for ; Fri, 12 Feb 2021 15:18:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 08A2E60C41 for ; Fri, 12 Feb 2021 15:18:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230047AbhBLPRp (ORCPT ); Fri, 12 Feb 2021 10:17:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48202 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231750AbhBLPRd (ORCPT ); Fri, 12 Feb 2021 10:17:33 -0500 Received: from mail-ed1-x529.google.com (mail-ed1-x529.google.com [IPv6:2a00:1450:4864:20::529]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 59ED3C06178B; Fri, 12 Feb 2021 07:16:19 -0800 (PST) Received: by mail-ed1-x529.google.com with SMTP id g21so73704edm.6; Fri, 12 Feb 2021 07:16:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=RdbgZt6+Ejd8o9yX3QH8zWAkNieI+hNY0rfhSAt45Bg=; b=SZqqc5U/A86HM9bbdAwU6IRRcZjOIhiKBcMd60KQiyl67X4+lFWyizRLdlyTr0heMq hyY47CFilr2OtOd1PNgUEN8fuWxRN7joWgMpIZt7SdXuk557EX+0cAoAHuMy+/cY3SsF e9VL3MJlJx8k3PGklOaCuo1CArEuh9vL+g0K0QYvPHO9Cwa750OrQABUqgh1OO+oHKIl 7zqEWoJFs7xJDQplndQHiUYI4QZCQwvWrG8KQ13Uv2Uul3Jj8Ukff7Le1dQzyKCobykM OAzqwwU6numx1g3vmRXLtndhrnCo25LT0LAN+mlCqxev676Z2u3vBF0kqo1i2JdP8Qwp ThIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=RdbgZt6+Ejd8o9yX3QH8zWAkNieI+hNY0rfhSAt45Bg=; b=Q+JzTixGzQOGua9HBQgSIu3cBL6rFVQV7Of7pAd1nh+LPlU1XzrD0kYTZfFVTXcNvB ftqb7NfA/+YcDucmm19XoV/dlSusi3uAG5S3O/PUPXMWaDfFXyATlnnKwjMyVnLqOSXi 1Ex00u0A7tuHDS+C2vxtyELH76+flEF9VuMxoFVGCSe5+GpiQxunf4tmVEDRwkBpHLI0 N3MJNEKcto1y1F8t524wMXOfKrXqbuegKFoOmVD0U1XkUEYhQnLLMJy2TvpkHTt9JB3P F4eF0nsAixY9wA3BophQzJ4lSJXhCsNUAl8vKe/rr8t+n7g7qvNAxMRJE9qdSogm7gYv jMwg== X-Gm-Message-State: AOAM533lafiq2Yv1P6HbrwSN1xB6kOMv0n356G0NkTVx1lXsEfJnOJsN NdqjGy+a+pN/cK5STEvDbhA= X-Google-Smtp-Source: ABdhPJwVY5bOoX+1HU+OD7DdvciDxZJr8jB/ArPHGd8J6J5S9bwr+FmI5cLUoej5auN6QMhY0zizzQ== X-Received: by 2002:a50:f318:: with SMTP id p24mr3898968edm.13.1613142977881; Fri, 12 Feb 2021 07:16:17 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:17 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 06/10] net: dsa: act as passthrough for bridge port flags Date: Fri, 12 Feb 2021 17:15:56 +0200 Message-Id: <20210212151600.3357121-7-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean There are multiple ways in which a PORT_BRIDGE_FLAGS attribute can be expressed by the bridge through switchdev, and not all of them can be emulated by DSA mid-layer API at the same time. One possible configuration is when the bridge offloads the port flags using a mask that has a single bit set - therefore only one feature should change. However, DSA currently groups together unicast and multicast flooding in the .port_egress_floods method, which limits our options when we try to add support for turning off broadcast flooding: do we extend .port_egress_floods with a third parameter which b53 and mv88e6xxx will ignore? But that means that the DSA layer, which currently implements the PRE_BRIDGE_FLAGS attribute all by itself, will see that .port_egress_floods is implemented, and will report that all 3 types of flooding are supported - not necessarily true. Another configuration is when the user specifies more than one flag at the same time, in the same netlink message. If we were to create one individual function per offloadable bridge port flag, we would limit the expressiveness of the switch driver of refusing certain combinations of flag values. For example, a switch may not have an explicit knob for flooding of unknown multicast, just for flooding in general. In that case, the only correct thing to do is to allow changes to BR_FLOOD and BR_MCAST_FLOOD in tandem, and never allow mismatched values. But having a separate .port_set_unicast_flood and .port_set_multicast_flood would not allow the driver to possibly reject that. Also, DSA doesn't consider it necessary to inform the driver that a SWITCHDEV_ATTR_ID_BRIDGE_MROUTER attribute was offloaded, because it just calls .port_egress_floods for the CPU port. When we'll add support for the plain SWITCHDEV_ATTR_ID_PORT_MROUTER, that will become a real problem because the flood settings will need to be held statefully in the DSA middle layer, otherwise changing the mrouter port attribute will impact the flooding attribute. And that's _assuming_ that the underlying hardware doesn't have anything else to do when a multicast router attaches to a port than flood unknown traffic to it. If it does, there will need to be a dedicated .port_set_mrouter anyway. So we need to let the DSA drivers see the exact form that the bridge passes this switchdev attribute in, otherwise we are standing in the way. Therefore we also need to use this form of language when communicating to the driver that it needs to configure its initial (before bridge join) and final (after bridge leave) port flags. The b53 and mv88e6xxx drivers are converted to the passthrough API and their implementation of .port_egress_floods is split into two: a function that configures unicast flooding and another for multicast. The mv88e6xxx implementation is quite hairy, and it turns out that the implementations of unknown unicast flooding are actually the same for 6185 and for 6352: behind the confusing names actually lie two individual bits: NO_UNKNOWN_MC -> FLOOD_UC = 0x4 = BIT(2) NO_UNKNOWN_UC -> FLOOD_MC = 0x8 = BIT(3) so there was no reason to entangle them in the first place. Whereas the 6185 writes to MV88E6185_PORT_CTL0_FORWARD_UNKNOWN of PORT_CTL0, which has the exact same bit index. I have left the implementations separate though, for the only reason that the names are different enough to confuse me, since I am not able to double-check with a user manual. The multicast flooding setting for 6185 is in a different register than for 6352 though. Signed-off-by: Vladimir Oltean --- Changes in v5: Adjust commit title. Changes in v4: - Adjust commit title and message. - Reintroduce the .port_pre_bridge_flags method. - Split the unicast and multicast flooding settings in mv88e6xxx and b53. Changes in v3: - Pass extack through the newly introduce dsa_port_change_brport_flags. Changes in v2: - Reordered with previous patch such that we don't need to introduce .port_pre_bridge_flags - Pass extack to drivers. drivers/net/dsa/b53/b53_common.c | 91 ++++++++++++----- drivers/net/dsa/b53/b53_priv.h | 2 - drivers/net/dsa/mv88e6xxx/chip.c | 163 ++++++++++++++++++++++++------- drivers/net/dsa/mv88e6xxx/chip.h | 6 +- drivers/net/dsa/mv88e6xxx/port.c | 52 +++++----- drivers/net/dsa/mv88e6xxx/port.h | 19 ++-- include/net/dsa.h | 10 +- net/dsa/dsa_priv.h | 9 +- net/dsa/port.c | 31 +++--- net/dsa/slave.c | 7 +- 10 files changed, 263 insertions(+), 127 deletions(-) diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index 23fc7225c8d1..72c75c7bdb65 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -510,6 +510,39 @@ void b53_imp_vlan_setup(struct dsa_switch *ds, int cpu_port) } EXPORT_SYMBOL(b53_imp_vlan_setup); +static void b53_port_set_ucast_flood(struct b53_device *dev, int port, + bool unicast) +{ + u16 uc; + + b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc); + if (unicast) + uc |= BIT(port); + else + uc &= ~BIT(port); + b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc); +} + +static void b53_port_set_mcast_flood(struct b53_device *dev, int port, + bool multicast) +{ + u16 mc; + + b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc); + if (multicast) + mc |= BIT(port); + else + mc &= ~BIT(port); + b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc); + + b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc); + if (multicast) + mc |= BIT(port); + else + mc &= ~BIT(port); + b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc); +} + int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) { struct b53_device *dev = ds->priv; @@ -522,7 +555,8 @@ int b53_enable_port(struct dsa_switch *ds, int port, struct phy_device *phy) cpu_port = dsa_to_port(ds, port)->cpu_dp->index; - b53_br_egress_floods(ds, port, true, true); + b53_port_set_ucast_flood(dev, port, true); + b53_port_set_mcast_flood(dev, port, true); if (dev->ops->irq_enable) ret = dev->ops->irq_enable(dev, port); @@ -655,7 +689,8 @@ static void b53_enable_cpu_port(struct b53_device *dev, int port) b53_brcm_hdr_setup(dev->ds, port); - b53_br_egress_floods(dev->ds, port, true, true); + b53_port_set_ucast_flood(dev, port, true); + b53_port_set_mcast_flood(dev, port, true); } static void b53_enable_mib(struct b53_device *dev) @@ -1916,37 +1951,37 @@ void b53_br_fast_age(struct dsa_switch *ds, int port) } EXPORT_SYMBOL(b53_br_fast_age); -int b53_br_egress_floods(struct dsa_switch *ds, int port, - bool unicast, bool multicast) +static int b53_br_flags_pre(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) { - struct b53_device *dev = ds->priv; - u16 uc, mc; - - b53_read16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, &uc); - if (unicast) - uc |= BIT(port); - else - uc &= ~BIT(port); - b53_write16(dev, B53_CTRL_PAGE, B53_UC_FLOOD_MASK, uc); + if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD)) + return -EINVAL; - b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc); - if (multicast) - mc |= BIT(port); - else - mc &= ~BIT(port); - b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc); + return 0; +} - b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc); - if (multicast) - mc |= BIT(port); - else - mc &= ~BIT(port); - b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc); +static int b53_br_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + if (flags.mask & BR_FLOOD) + b53_port_set_ucast_flood(ds->priv, port, + !!(flags.val & BR_FLOOD)); + if (flags.mask & BR_MCAST_FLOOD) + b53_port_set_mcast_flood(ds->priv, port, + !!(flags.val & BR_MCAST_FLOOD)); return 0; +} +static int b53_set_mrouter(struct dsa_switch *ds, int port, bool mrouter, + struct netlink_ext_ack *extack) +{ + b53_port_set_mcast_flood(ds->priv, port, mrouter); + + return 0; } -EXPORT_SYMBOL(b53_br_egress_floods); static bool b53_possible_cpu_port(struct dsa_switch *ds, int port) { @@ -2187,9 +2222,11 @@ static const struct dsa_switch_ops b53_switch_ops = { .set_mac_eee = b53_set_mac_eee, .port_bridge_join = b53_br_join, .port_bridge_leave = b53_br_leave, + .port_pre_bridge_flags = b53_br_flags_pre, + .port_bridge_flags = b53_br_flags, + .port_set_mrouter = b53_set_mrouter, .port_stp_state_set = b53_br_set_stp_state, .port_fast_age = b53_br_fast_age, - .port_egress_floods = b53_br_egress_floods, .port_vlan_filtering = b53_vlan_filtering, .port_vlan_add = b53_vlan_add, .port_vlan_del = b53_vlan_del, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index 0d2cc0453bef..ae72ef46b0b6 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -326,8 +326,6 @@ int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge); void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *bridge); void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state); void b53_br_fast_age(struct dsa_switch *ds, int port); -int b53_br_egress_floods(struct dsa_switch *ds, int port, - bool unicast, bool multicast); int b53_setup_devlink_resources(struct dsa_switch *ds); void b53_port_event(struct dsa_switch *ds, int port); void b53_phylink_validate(struct dsa_switch *ds, int port, diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index ae0b490f00cd..0ef1fadfec68 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -2434,12 +2434,20 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port) { struct dsa_switch *ds = chip->ds; bool flood; + int err; /* Upstream ports flood frames with unknown unicast or multicast DA */ flood = dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port); - if (chip->info->ops->port_set_egress_floods) - return chip->info->ops->port_set_egress_floods(chip, port, - flood, flood); + if (chip->info->ops->port_set_ucast_flood) { + err = chip->info->ops->port_set_ucast_flood(chip, port, flood); + if (err) + return err; + } + if (chip->info->ops->port_set_mcast_flood) { + err = chip->info->ops->port_set_mcast_flood(chip, port, flood); + if (err) + return err; + } return 0; } @@ -3239,7 +3247,8 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, @@ -3278,7 +3287,8 @@ static const struct mv88e6xxx_ops mv88e6095_ops = { .port_sync_link = mv88e6185_port_sync_link, .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_set_frame_mode = mv88e6085_port_set_frame_mode, - .port_set_egress_floods = mv88e6185_port_set_egress_floods, + .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, + .port_set_mcast_flood = mv88e6185_port_set_default_forward, .port_set_upstream_port = mv88e6095_port_set_upstream_port, .port_get_cmode = mv88e6185_port_get_cmode, .port_setup_message_port = mv88e6xxx_setup_message_port, @@ -3313,7 +3323,8 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, @@ -3357,7 +3368,8 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .port_sync_link = mv88e6xxx_port_sync_link, .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_set_frame_mode = mv88e6085_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_get_cmode = mv88e6185_port_get_cmode, @@ -3393,7 +3405,8 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6185_port_set_egress_floods, + .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, + .port_set_mcast_flood = mv88e6185_port_set_default_forward, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_upstream_port = mv88e6095_port_set_upstream_port, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, @@ -3437,7 +3450,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .port_max_speed_mode = mv88e6341_port_max_speed_mode, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -3487,7 +3501,8 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -3565,7 +3580,8 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -3609,7 +3625,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .port_tag_remap = mv88e6095_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -3660,7 +3677,8 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -3704,7 +3722,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .port_tag_remap = mv88e6095_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -3755,7 +3774,8 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { .port_sync_link = mv88e6185_port_sync_link, .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_set_frame_mode = mv88e6085_port_set_frame_mode, - .port_set_egress_floods = mv88e6185_port_set_egress_floods, + .port_set_ucast_flood = mv88e6185_port_set_forward_unknown, + .port_set_mcast_flood = mv88e6185_port_set_default_forward, .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, .port_set_upstream_port = mv88e6095_port_set_upstream_port, .port_set_pause = mv88e6185_port_set_pause, @@ -3800,7 +3820,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_pause_limit = mv88e6390_port_pause_limit, @@ -3860,7 +3881,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_pause_limit = mv88e6390_port_pause_limit, @@ -3919,7 +3941,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .port_max_speed_mode = mv88e6390_port_max_speed_mode, .port_tag_remap = mv88e6390_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_pause_limit = mv88e6390_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -3979,7 +4002,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .port_tag_remap = mv88e6095_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -4037,7 +4061,8 @@ static const struct mv88e6xxx_ops mv88e6250_ops = { .port_set_speed_duplex = mv88e6250_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, .port_pause_limit = mv88e6097_port_pause_limit, @@ -4077,7 +4102,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_pause_limit = mv88e6390_port_pause_limit, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -4136,7 +4162,8 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -4179,7 +4206,8 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -4222,7 +4250,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .port_max_speed_mode = mv88e6341_port_max_speed_mode, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -4275,7 +4304,8 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -4316,7 +4346,8 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -4362,7 +4393,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .port_tag_remap = mv88e6095_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -4424,7 +4456,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -4488,7 +4521,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, - .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ucast_flood = mv88e6352_port_set_ucast_flood, + .port_set_mcast_flood = mv88e6352_port_set_mcast_flood, .port_set_ether_type = mv88e6351_port_set_ether_type, .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, @@ -5364,17 +5398,72 @@ static void mv88e6xxx_port_mirror_del(struct dsa_switch *ds, int port, mutex_unlock(&chip->reg_lock); } -static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, - bool unicast, bool multicast) +static int mv88e6xxx_port_pre_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct mv88e6xxx_chip *chip = ds->priv; + const struct mv88e6xxx_ops *ops; + + if (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD)) + return -EINVAL; + + ops = chip->info->ops; + + if ((flags.mask & BR_FLOOD) && !ops->port_set_ucast_flood) + return -EINVAL; + + if ((flags.mask & BR_MCAST_FLOOD) && !ops->port_set_mcast_flood) + return -EINVAL; + + return 0; +} + +static int mv88e6xxx_port_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) { struct mv88e6xxx_chip *chip = ds->priv; int err = -EOPNOTSUPP; mv88e6xxx_reg_lock(chip); - if (chip->info->ops->port_set_egress_floods) - err = chip->info->ops->port_set_egress_floods(chip, port, - unicast, - multicast); + + if (flags.mask & BR_FLOOD) { + bool unicast = !!(flags.val & BR_FLOOD); + + err = chip->info->ops->port_set_ucast_flood(chip, port, + unicast); + if (err) + goto out; + } + + if (flags.mask & BR_MCAST_FLOOD) { + bool multicast = !!(flags.val & BR_MCAST_FLOOD); + + err = chip->info->ops->port_set_mcast_flood(chip, port, + multicast); + if (err) + goto out; + } + +out: + mv88e6xxx_reg_unlock(chip); + + return err; +} + +static int mv88e6xxx_port_set_mrouter(struct dsa_switch *ds, int port, + bool mrouter, + struct netlink_ext_ack *extack) +{ + struct mv88e6xxx_chip *chip = ds->priv; + int err; + + if (!chip->info->ops->port_set_mcast_flood) + return -EOPNOTSUPP; + + mv88e6xxx_reg_lock(chip); + err = chip->info->ops->port_set_mcast_flood(chip, port, mrouter); mv88e6xxx_reg_unlock(chip); return err; @@ -5678,7 +5767,9 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .set_ageing_time = mv88e6xxx_set_ageing_time, .port_bridge_join = mv88e6xxx_port_bridge_join, .port_bridge_leave = mv88e6xxx_port_bridge_leave, - .port_egress_floods = mv88e6xxx_port_egress_floods, + .port_pre_bridge_flags = mv88e6xxx_port_pre_bridge_flags, + .port_bridge_flags = mv88e6xxx_port_bridge_flags, + .port_set_mrouter = mv88e6xxx_port_set_mrouter, .port_stp_state_set = mv88e6xxx_port_stp_state_set, .port_fast_age = mv88e6xxx_port_fast_age, .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 788b3f585ef3..a57c8886f3ac 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -454,8 +454,10 @@ struct mv88e6xxx_ops { int (*port_set_frame_mode)(struct mv88e6xxx_chip *chip, int port, enum mv88e6xxx_frame_mode mode); - int (*port_set_egress_floods)(struct mv88e6xxx_chip *chip, int port, - bool unicast, bool multicast); + int (*port_set_ucast_flood)(struct mv88e6xxx_chip *chip, int port, + bool unicast); + int (*port_set_mcast_flood)(struct mv88e6xxx_chip *chip, int port, + bool multicast); int (*port_set_ether_type)(struct mv88e6xxx_chip *chip, int port, u16 etype); int (*port_set_jumbo_size)(struct mv88e6xxx_chip *chip, int port, diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 4b46e10a2dde..4561f289ab76 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -789,8 +789,8 @@ int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); } -static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, - int port, bool unicast) +int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, + int port, bool unicast) { int err; u16 reg; @@ -807,8 +807,8 @@ static int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); } -int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, - bool unicast, bool multicast) +int mv88e6352_port_set_ucast_flood(struct mv88e6xxx_chip *chip, int port, + bool unicast) { int err; u16 reg; @@ -817,16 +817,28 @@ int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, if (err) return err; - reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK; + if (unicast) + reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC; + else + reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC; + + return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); +} + +int mv88e6352_port_set_mcast_flood(struct mv88e6xxx_chip *chip, int port, + bool multicast) +{ + int err; + u16 reg; + + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_CTL0, ®); + if (err) + return err; - if (unicast && multicast) - reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA; - else if (unicast) - reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA; - else if (multicast) - reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA; + if (multicast) + reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC; else - reg |= MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA; + reg &= ~MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC; return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL0, reg); } @@ -1013,8 +1025,8 @@ static const char * const mv88e6xxx_port_8021q_mode_names[] = { [MV88E6XXX_PORT_CTL2_8021Q_MODE_SECURE] = "Secure", }; -static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, - int port, bool multicast) +int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, + int port, bool multicast) { int err; u16 reg; @@ -1031,18 +1043,6 @@ static int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_CTL2, reg); } -int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, - bool unicast, bool multicast) -{ - int err; - - err = mv88e6185_port_set_forward_unknown(chip, port, unicast); - if (err) - return err; - - return mv88e6185_port_set_default_forward(chip, port, multicast); -} - int mv88e6095_port_set_upstream_port(struct mv88e6xxx_chip *chip, int port, int upstream_port) { diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index a729bba050df..e6d0eaa6aa1d 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -154,11 +154,8 @@ #define MV88E6185_PORT_CTL0_USE_IP 0x0020 #define MV88E6185_PORT_CTL0_USE_TAG 0x0010 #define MV88E6185_PORT_CTL0_FORWARD_UNKNOWN 0x0004 -#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_MASK 0x000c -#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_DA 0x0000 -#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_MC_DA 0x0004 -#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_NO_UNKNOWN_UC_DA 0x0008 -#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_ALL_UNKNOWN_DA 0x000c +#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_UC 0x0004 +#define MV88E6352_PORT_CTL0_EGRESS_FLOODS_MC 0x0008 #define MV88E6XXX_PORT_CTL0_STATE_MASK 0x0003 #define MV88E6XXX_PORT_CTL0_STATE_DISABLED 0x0000 #define MV88E6XXX_PORT_CTL0_STATE_BLOCKING 0x0001 @@ -343,10 +340,14 @@ int mv88e6085_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, enum mv88e6xxx_frame_mode mode); int mv88e6351_port_set_frame_mode(struct mv88e6xxx_chip *chip, int port, enum mv88e6xxx_frame_mode mode); -int mv88e6185_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, - bool unicast, bool multicast); -int mv88e6352_port_set_egress_floods(struct mv88e6xxx_chip *chip, int port, - bool unicast, bool multicast); +int mv88e6185_port_set_forward_unknown(struct mv88e6xxx_chip *chip, + int port, bool unicast); +int mv88e6185_port_set_default_forward(struct mv88e6xxx_chip *chip, + int port, bool multicast); +int mv88e6352_port_set_ucast_flood(struct mv88e6xxx_chip *chip, int port, + bool unicast); +int mv88e6352_port_set_mcast_flood(struct mv88e6xxx_chip *chip, int port, + bool multicast); int mv88e6352_port_set_policy(struct mv88e6xxx_chip *chip, int port, enum mv88e6xxx_policy_mapping mapping, enum mv88e6xxx_policy_action action); diff --git a/include/net/dsa.h b/include/net/dsa.h index d8de23ce7221..74457aaffec7 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -626,8 +626,14 @@ struct dsa_switch_ops { void (*port_stp_state_set)(struct dsa_switch *ds, int port, u8 state); void (*port_fast_age)(struct dsa_switch *ds, int port); - int (*port_egress_floods)(struct dsa_switch *ds, int port, - bool unicast, bool multicast); + int (*port_pre_bridge_flags)(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack); + int (*port_bridge_flags)(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack); + int (*port_set_mrouter)(struct dsa_switch *ds, int port, bool mrouter, + struct netlink_ext_ack *extack); /* * VLAN support diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index bc835f3de2be..f5949b39f6f7 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -184,10 +184,13 @@ int dsa_port_mdb_add(const struct dsa_port *dp, int dsa_port_mdb_del(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb); int dsa_port_pre_bridge_flags(const struct dsa_port *dp, - struct switchdev_brport_flags flags); + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack); int dsa_port_bridge_flags(const struct dsa_port *dp, - struct switchdev_brport_flags flags); -int dsa_port_mrouter(struct dsa_port *dp, bool mrouter); + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack); +int dsa_port_mrouter(struct dsa_port *dp, bool mrouter, + struct netlink_ext_ack *extack); int dsa_port_vlan_add(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan); int dsa_port_vlan_del(struct dsa_port *dp, diff --git a/net/dsa/port.c b/net/dsa/port.c index 368064dfd93e..80e6471a7a5c 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -140,7 +140,7 @@ static void dsa_port_change_brport_flags(struct dsa_port *dp, tmp.val = flags.val & BIT(flag); tmp.mask = BIT(flag); - dsa_port_bridge_flags(dp, tmp); + dsa_port_bridge_flags(dp, tmp, NULL); } } @@ -425,41 +425,38 @@ int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock) } int dsa_port_pre_bridge_flags(const struct dsa_port *dp, - struct switchdev_brport_flags flags) + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) { struct dsa_switch *ds = dp->ds; - if (!ds->ops->port_egress_floods || - (flags.mask & ~(BR_FLOOD | BR_MCAST_FLOOD))) + if (!ds->ops->port_pre_bridge_flags) return -EINVAL; - return 0; + return ds->ops->port_pre_bridge_flags(ds, dp->index, flags, extack); } int dsa_port_bridge_flags(const struct dsa_port *dp, - struct switchdev_brport_flags flags) + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) { struct dsa_switch *ds = dp->ds; - int port = dp->index; - int err = 0; - if (ds->ops->port_egress_floods) - err = ds->ops->port_egress_floods(ds, port, - flags.val & BR_FLOOD, - flags.val & BR_MCAST_FLOOD); + if (!ds->ops->port_bridge_flags) + return -EINVAL; - return err; + return ds->ops->port_bridge_flags(ds, dp->index, flags, extack); } -int dsa_port_mrouter(struct dsa_port *dp, bool mrouter) +int dsa_port_mrouter(struct dsa_port *dp, bool mrouter, + struct netlink_ext_ack *extack) { struct dsa_switch *ds = dp->ds; - int port = dp->index; - if (!ds->ops->port_egress_floods) + if (!ds->ops->port_set_mrouter) return -EOPNOTSUPP; - return ds->ops->port_egress_floods(ds, port, true, mrouter); + return ds->ops->port_set_mrouter(ds, dp->index, mrouter, extack); } int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu, diff --git a/net/dsa/slave.c b/net/dsa/slave.c index be29008477d3..8c9a41a7209a 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -292,13 +292,14 @@ static int dsa_slave_port_attr_set(struct net_device *dev, ret = dsa_port_ageing_time(dp, attr->u.ageing_time); break; case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: - ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags); + ret = dsa_port_pre_bridge_flags(dp, attr->u.brport_flags, + extack); break; case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: - ret = dsa_port_bridge_flags(dp, attr->u.brport_flags); + ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, extack); break; case SWITCHDEV_ATTR_ID_BRIDGE_MROUTER: - ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter); + ret = dsa_port_mrouter(dp->cpu_dp, attr->u.mrouter, extack); break; default: ret = -EOPNOTSUPP; From patchwork Fri Feb 12 15:15:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382101 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A555BC433DB for ; Fri, 12 Feb 2021 15:18:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 61A2464DB1 for ; Fri, 12 Feb 2021 15:18:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232032AbhBLPR5 (ORCPT ); Fri, 12 Feb 2021 10:17:57 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48212 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231753AbhBLPRe (ORCPT ); Fri, 12 Feb 2021 10:17:34 -0500 Received: from mail-ej1-x62f.google.com (mail-ej1-x62f.google.com [IPv6:2a00:1450:4864:20::62f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BC26AC06178C; Fri, 12 Feb 2021 07:16:20 -0800 (PST) Received: by mail-ej1-x62f.google.com with SMTP id f14so16222249ejc.8; Fri, 12 Feb 2021 07:16:20 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=9apr4CU9ROkXpvdUS3JqoM5muZRLGcdC/mdCAjUO/2I=; b=qq/gRN94YuTLfdmLPHGrMIymx/OC2yPfwrCmUNWPUscQWFrnpX9Qp5prLEZZ5Smiqo +v48lKSnWO0bE2Yv4ibxQkAwGA4SuHUXkq/uoDWJyALgI/GCIuNFyEafXA0mWQbKTGsv AzVIlmgvxYH2bnlddkYkKKJss1qZQHIrqiaPtp0LoxhXt+cdWFUh4zl64DGC+L5Be7ym jWRZmZlxilq64BzvYo8meIs3IyHBvOzUAZ5xf3Sjt1pEAH++M6p4svBVQUhJN/OkeQ+Z LJDTJZ7Q+M2FTnRF/S5qeT/x4FQFCAT3v0OSc28sNm2WvN4suT9W58TDscjR/wDX0RFu j+Ag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=9apr4CU9ROkXpvdUS3JqoM5muZRLGcdC/mdCAjUO/2I=; b=Z2Mm6wE5NAja0Gg6+vswyCOSOti5leeX4AiVW7l1XocwoPRSIAdmceVOlRlOtIBcXf WFU2sxF4LviOjzJf969rWqSTyuBgR3J9itnFV7ZyeM6xAPizdLPNh0/KHmgoLdO2qAUH ZWjjVCEI1+1TONMPIoUyQQ5vq0LRUgdVM5zwy4a7xJFse51zOinF8hVXtgkGEPzytUt/ /Dzq4rH6vpOuNtOazung//myHWx9CZRCWl32eINskKCi6Uf+thqN4oZLft5jbDrryPHO qB2JxIqbTFbQ6h7uedf/NkixYzRrkDA+tHXfBDogD8PAB2KV7IvQ6jZQ/EXVJqk6Xsau DaLw== X-Gm-Message-State: AOAM531eUsCiBwr42mbfsJBv0ET/solhwNdNWrcFJrfB9vg02ITIECT/ oaHmvs9Yp5D0AIs75HTFncM= X-Google-Smtp-Source: ABdhPJwHssbN/+yfFPMDwZu6omt1qgfcrLFY+m+hvPdQyX857QadMgG6m5v5GhoDlYC2fYMeyC7HYQ== X-Received: by 2002:a17:906:378d:: with SMTP id n13mr3387451ejc.386.1613142979490; Fri, 12 Feb 2021 07:16:19 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:19 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 07/10] net: dsa: felix: restore multicast flood to CPU when NPI tagger reinitializes Date: Fri, 12 Feb 2021 17:15:57 +0200 Message-Id: <20210212151600.3357121-8-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean ocelot_init sets up PGID_MC to include the CPU port module, and that is fine, but the ocelot-8021q tagger removes the CPU port module from the unknown multicast replicator. So after a transition from the default ocelot tagger towards ocelot-8021q and then again towards ocelot, multicast flooding towards the CPU port module will be disabled. Fixes: e21268efbe26 ("net: dsa: felix: perform switch setup for tag_8021q") Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- Changes in v5: Patch is new. drivers/net/dsa/ocelot/felix.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 386468e66c41..ae11d3f030ac 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -411,6 +411,7 @@ static int felix_setup_tag_npi(struct dsa_switch *ds, int cpu) */ cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_UC); + ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_MC); return 0; } From patchwork Fri Feb 12 15:15:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382102 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9B47BC43331 for ; Fri, 12 Feb 2021 15:18:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5880064DF2 for ; Fri, 12 Feb 2021 15:18:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231317AbhBLPRx (ORCPT ); Fri, 12 Feb 2021 10:17:53 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48214 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231754AbhBLPRe (ORCPT ); Fri, 12 Feb 2021 10:17:34 -0500 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 37C81C061793; Fri, 12 Feb 2021 07:16:22 -0800 (PST) Received: by mail-ed1-x52d.google.com with SMTP id g21so73880edm.6; Fri, 12 Feb 2021 07:16:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=dHN/KEqqL5oOLZEZeyQA7jzjeIc7NEY7uPpaXIEmtwA=; b=gt82nsMmAQ+WIrw+CtYGDCHn8MzrKAE6EnVDlgcbV2yi2XhjPPVQL0/0OGYgl8G5kV GpRMlrWB9M8kxqxmTN3TzATAFFZr4oQB4cI2HNrw6u35b1eBmzOCIbMJKk+sX2NKRpj0 b1FHZafx5E4aPfHjhhLJLQR+tvTzeACZJEO9wuLy75frNpgosMkmos4bdHnXlIWeHSox KzjIsH+38IjJUYYdZxsZpGwstSWfD/breQdAn7uJV2UfsBkZl6/q7C+GhDeCYcI0rY6h 51DLov0vgem8sp+M3ZDlZmNfrwgD4pzhc/kNWNzuD/gIc8dlbUUb8kPP5QuRK+zP5G9z wVCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=dHN/KEqqL5oOLZEZeyQA7jzjeIc7NEY7uPpaXIEmtwA=; b=MRLbdhC8LIr7cLi3WEjKGovkyO6CKU7OtyrRdeqe2YxSyQ/XJ09lZbDyd33rKN7gTL 2N03cIXh09Pg7Jd+10DJ4Q35MwkotlnXZJ+oAF4NtprXShUdbzbDk9Nlps51EidRT8m3 Pqojsp5MARHjNlKckC/MQ2C41LCjPz60LhRagRoHELD4ITakplgw//VuFjVihJjMcqxw AO5D5m+90cpjTIFZxBnJMJ267+6ZtIPpuv3stshUoE35GHub2fFoJmzhY9NJpD9zQz4b V2q39ZsGTA8et/qdTyuempokBWLXxVsB3j13xspgsz/JRvoCb1xxvoF4MVVTBim0Fwr+ Sfvw== X-Gm-Message-State: AOAM532O3EKJ6bhO+dV/NCHGQv1J0C7NBtHYmcfwpDhn0bJ62nEolHZL nOK3xQOHZkQZEEuSZjPVn6I= X-Google-Smtp-Source: ABdhPJxERN6QqoEHDrAuCtFFPYQ0A+bahP95QHpcJVPvMzT8BgrDS2zVg/HPSRHhwwDrXyiNcB3OnA== X-Received: by 2002:a05:6402:100b:: with SMTP id c11mr3820883edu.193.1613142980909; Fri, 12 Feb 2021 07:16:20 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:20 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 08/10] net: mscc: ocelot: use separate flooding PGID for broadcast Date: Fri, 12 Feb 2021 17:15:58 +0200 Message-Id: <20210212151600.3357121-9-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean In preparation of offloading the bridge port flags which have independent settings for unknown multicast and for broadcast, we should also start reserving one destination Port Group ID for the flooding of broadcast packets, to allow configuring it individually. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli --- Changes in v5: Restore the PGID_BC value from the ocelot-8021q DSA tagger setup code too. Changes in v4: None. Changes in v3: None. Changes in v2: None. drivers/net/dsa/ocelot/felix.c | 2 ++ drivers/net/ethernet/mscc/ocelot.c | 13 ++++++++----- include/soc/mscc/ocelot.h | 15 ++++++++------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index ae11d3f030ac..00b053d8294f 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -299,6 +299,7 @@ static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu) cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_UC); ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_MC); + ocelot_rmw_rix(ocelot, 0, cpu_flood, ANA_PGID_PGID, PGID_BC); felix->dsa_8021q_ctx = kzalloc(sizeof(*felix->dsa_8021q_ctx), GFP_KERNEL); @@ -412,6 +413,7 @@ static int felix_setup_tag_npi(struct dsa_switch *ds, int cpu) cpu_flood = ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)); ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_UC); ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_MC); + ocelot_rmw_rix(ocelot, cpu_flood, cpu_flood, ANA_PGID_PGID, PGID_BC); return 0; } diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 1654a6e22a7d..1a31598e2ae6 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1716,7 +1716,7 @@ int ocelot_init(struct ocelot *ocelot) /* Setup flooding PGIDs */ for (i = 0; i < ocelot->num_flooding_pgids; i++) ocelot_write_rix(ocelot, ANA_FLOODING_FLD_MULTICAST(PGID_MC) | - ANA_FLOODING_FLD_BROADCAST(PGID_MC) | + ANA_FLOODING_FLD_BROADCAST(PGID_BC) | ANA_FLOODING_FLD_UNICAST(PGID_UC), ANA_FLOODING, i); ocelot_write(ocelot, ANA_FLOODING_IPMC_FLD_MC6_DATA(PGID_MCIPV6) | @@ -1737,15 +1737,18 @@ int ocelot_init(struct ocelot *ocelot) ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_SRC + port); } - /* Allow broadcast MAC frames. */ for_each_nonreserved_multicast_dest_pgid(ocelot, i) { u32 val = ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports - 1, 0)); ocelot_write_rix(ocelot, val, ANA_PGID_PGID, i); } - ocelot_write_rix(ocelot, - ANA_PGID_PGID_PGID(GENMASK(ocelot->num_phys_ports, 0)), - ANA_PGID_PGID, PGID_MC); + /* Allow broadcast and unknown L2 multicast to the CPU. */ + ocelot_rmw_rix(ocelot, ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)), + ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)), + ANA_PGID_PGID, PGID_MC); + ocelot_rmw_rix(ocelot, ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)), + ANA_PGID_PGID_PGID(BIT(ocelot->num_phys_ports)), + ANA_PGID_PGID, PGID_BC); ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV4); ocelot_write_rix(ocelot, 0, ANA_PGID_PGID, PGID_MCIPV6); diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index bfce3df61bfd..9acbef1416f1 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -54,16 +54,17 @@ * PGID_CPU: used for whitelisting certain MAC addresses, such as the addresses * of the switch port net devices, towards the CPU port module. * PGID_UC: the flooding destinations for unknown unicast traffic. - * PGID_MC: the flooding destinations for broadcast and non-IP multicast - * traffic. + * PGID_MC: the flooding destinations for non-IP multicast traffic. * PGID_MCIPV4: the flooding destinations for IPv4 multicast traffic. * PGID_MCIPV6: the flooding destinations for IPv6 multicast traffic. + * PGID_BC: the flooding destinations for broadcast traffic. */ -#define PGID_CPU 59 -#define PGID_UC 60 -#define PGID_MC 61 -#define PGID_MCIPV4 62 -#define PGID_MCIPV6 63 +#define PGID_CPU 58 +#define PGID_UC 59 +#define PGID_MC 60 +#define PGID_MCIPV4 61 +#define PGID_MCIPV6 62 +#define PGID_BC 63 #define for_each_unicast_dest_pgid(ocelot, pgid) \ for ((pgid) = 0; \ From patchwork Fri Feb 12 15:15:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382575 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9A9B1C433E0 for ; Fri, 12 Feb 2021 15:18:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3BF4064DB2 for ; Fri, 12 Feb 2021 15:18:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230286AbhBLPSA (ORCPT ); Fri, 12 Feb 2021 10:18:00 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48222 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231764AbhBLPRg (ORCPT ); Fri, 12 Feb 2021 10:17:36 -0500 Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com [IPv6:2a00:1450:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AFA96C061794; Fri, 12 Feb 2021 07:16:23 -0800 (PST) Received: by mail-ej1-x632.google.com with SMTP id jj19so16280691ejc.4; Fri, 12 Feb 2021 07:16:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=wTIzFT+PgPAUqTo/z74g0XCLg8NJH/Gc9vxgNHggcXA=; b=j2ztp3D8EyBGtVTgegygOT0NAWCPSBHP6CPhLleB+9JYjn9KZWysG1WJgM/5IBT4Yx TDmQtFSeN2ty7iyXmaSgslC6PyrmKSaxO7O3RT5xwU6rkMimNj4F5/35VJWNOAcPRSgm qwkHw24qjsCI1u8ZCZaxdbmGUnuq3MVWi1K/q+JMg5epDj5JJMGIzsH8GUo7KH/iEYCP XGSxLgvHQi9se3YU1wdpnSDNY+j5q+ns+M2sqKJtlzbwfBWHZXzcxd+78B/FG+nN3h4S KJhwOu5rmJ5BunUzK+TDXT0SRz53HnWmE9Fe+p3H0An+sfdej1NP1RtOYVLe52NdWFQe kwNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wTIzFT+PgPAUqTo/z74g0XCLg8NJH/Gc9vxgNHggcXA=; b=i8iIO+2ruiLiLbimlfZdN9xPOAlBgmbiZpgtYSmHyr+M3bZ2qHCMnZ1GiCS3GkvCHx CGal+C2Zy4bOwneUc9t9RX28VdvFiBtbKRBFq38W2i4ggmXNBOka5004fZcGX/FKJXtf C2JD2tukRWfrrJnxC9G/eX22zIhXx/KuEXZuFFGErVJQ9gubLrYoPlFLBzhrqOVOAbFt gIO9xUrG5ecO116rteBrlyz8l0hAc9Eq6JAygShnOHml09JGxdWMgZ1TbHEMxfrU1b+1 Oqn0uhLrUGKrx7qV04iccvFus7Wx0UkYuAfxNdT+L6J5rrFkxi4M2KtfUefCkJZcL6zj T31Q== X-Gm-Message-State: AOAM533pXdeSoVvGN99vaVDh9fVWk/XMBiixR20aSWDYNQn9VJy3+gWP mc26eosq8y2cDY0QlqSMKr8= X-Google-Smtp-Source: ABdhPJwAcqlj3tCQcFrXdtEiEYP+BHzdpD8qcvhl5/nMbbusYajPEvXQZGZ20dHQ6Ud8dawAl0whOQ== X-Received: by 2002:a17:907:ea3:: with SMTP id ho35mr3461618ejc.396.1613142982430; Fri, 12 Feb 2021 07:16:22 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:22 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 09/10] net: mscc: ocelot: offload bridge port flags to device Date: Fri, 12 Feb 2021 17:15:59 +0200 Message-Id: <20210212151600.3357121-10-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean We should not be unconditionally enabling address learning, since doing that is actively detrimential when a port is standalone and not offloading a bridge. Namely, if a port in the switch is standalone and others are offloading the bridge, then we could enter a situation where we learn an address towards the standalone port, but the bridged ports could not forward the packet there, because the CPU is the only path between the standalone and the bridged ports. The solution of course is to not enable address learning unless the bridge asks for it. We need to set up the initial port flags for no learning and flooding everything, and also when the port joins and leaves the bridge. The flood configuration was already configured ok for standalone mode in ocelot_init, we just need to disable learning in ocelot_init_port. Signed-off-by: Vladimir Oltean Reviewed-by: Alexandre Belloni Reviewed-by: Florian Fainelli --- Changes in v5: None. Changes in v4: - Applying the bridge port flags by hand at bridge join and leave, like DSA and other switchdev drivers. - Put every bridge port flag in a separate function. - Export ocelot_port_pre_bridge_flags for felix DSA to use. Changes in v3: None. Changes in v2: - Disable learning in ocelot_init_port. - Keep a single bool ocelot_port->learn_ena instead of ocelot_port->brport_flags. - Stop touching the brport_flags from ocelot_port_bridge_leave (which was a leftover). drivers/net/dsa/ocelot/felix.c | 22 +++++++ drivers/net/ethernet/mscc/ocelot.c | 87 +++++++++++++++++++++++++- drivers/net/ethernet/mscc/ocelot_net.c | 49 +++++++++++++-- include/soc/mscc/ocelot.h | 5 ++ 4 files changed, 158 insertions(+), 5 deletions(-) diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 00b053d8294f..d3180b0f2307 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -556,6 +556,26 @@ static void felix_bridge_stp_state_set(struct dsa_switch *ds, int port, return ocelot_bridge_stp_state_set(ocelot, port, state); } +static int felix_pre_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags val, + struct netlink_ext_ack *extack) +{ + struct ocelot *ocelot = ds->priv; + + return ocelot_port_pre_bridge_flags(ocelot, port, val); +} + +static int felix_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags val, + struct netlink_ext_ack *extack) +{ + struct ocelot *ocelot = ds->priv; + + ocelot_port_bridge_flags(ocelot, port, val); + + return 0; +} + static int felix_bridge_join(struct dsa_switch *ds, int port, struct net_device *br) { @@ -1376,6 +1396,8 @@ const struct dsa_switch_ops felix_switch_ops = { .port_fdb_del = felix_fdb_del, .port_mdb_add = felix_mdb_add, .port_mdb_del = felix_mdb_del, + .port_pre_bridge_flags = felix_pre_bridge_flags, + .port_bridge_flags = felix_bridge_flags, .port_bridge_join = felix_bridge_join, .port_bridge_leave = felix_bridge_leave, .port_lag_join = felix_lag_join, diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index 1a31598e2ae6..d1a9cdbf7a3e 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1038,6 +1038,7 @@ EXPORT_SYMBOL(ocelot_apply_bridge_fwd_mask); void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state) { + struct ocelot_port *ocelot_port = ocelot->ports[port]; u32 port_cfg; if (!(BIT(port) & ocelot->bridge_mask)) @@ -1050,7 +1051,8 @@ void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state) ocelot->bridge_fwd_mask |= BIT(port); fallthrough; case BR_STATE_LEARNING: - port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA; + if (ocelot_port->learn_ena) + port_cfg |= ANA_PORT_PORT_CFG_LEARN_ENA; break; default: @@ -1534,6 +1536,86 @@ int ocelot_get_max_mtu(struct ocelot *ocelot, int port) } EXPORT_SYMBOL(ocelot_get_max_mtu); +static void ocelot_port_set_learning(struct ocelot *ocelot, int port, + bool enabled) +{ + struct ocelot_port *ocelot_port = ocelot->ports[port]; + u32 val = 0; + + if (enabled) + val = ANA_PORT_PORT_CFG_LEARN_ENA; + + ocelot_rmw_gix(ocelot, val, ANA_PORT_PORT_CFG_LEARN_ENA, + ANA_PORT_PORT_CFG, port); + + ocelot_port->learn_ena = enabled; +} + +static void ocelot_port_set_ucast_flood(struct ocelot *ocelot, int port, + bool enabled) +{ + u32 val = 0; + + if (enabled) + val = BIT(port); + + ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_UC); +} + +static void ocelot_port_set_mcast_flood(struct ocelot *ocelot, int port, + bool enabled) +{ + u32 val = 0; + + if (enabled) + val = BIT(port); + + ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_MC); +} + +static void ocelot_port_set_bcast_flood(struct ocelot *ocelot, int port, + bool enabled) +{ + u32 val = 0; + + if (enabled) + val = BIT(port); + + ocelot_rmw_rix(ocelot, val, BIT(port), ANA_PGID_PGID, PGID_BC); +} + +int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port, + struct switchdev_brport_flags flags) +{ + if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | + BR_BCAST_FLOOD)) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(ocelot_port_pre_bridge_flags); + +void ocelot_port_bridge_flags(struct ocelot *ocelot, int port, + struct switchdev_brport_flags flags) +{ + if (flags.mask & BR_LEARNING) + ocelot_port_set_learning(ocelot, port, + !!(flags.val & BR_LEARNING)); + + if (flags.mask & BR_FLOOD) + ocelot_port_set_ucast_flood(ocelot, port, + !!(flags.val & BR_FLOOD)); + + if (flags.mask & BR_MCAST_FLOOD) + ocelot_port_set_mcast_flood(ocelot, port, + !!(flags.val & BR_MCAST_FLOOD)); + + if (flags.mask & BR_BCAST_FLOOD) + ocelot_port_set_bcast_flood(ocelot, port, + !!(flags.val & BR_BCAST_FLOOD)); +} +EXPORT_SYMBOL(ocelot_port_bridge_flags); + void ocelot_init_port(struct ocelot *ocelot, int port) { struct ocelot_port *ocelot_port = ocelot->ports[port]; @@ -1583,6 +1665,9 @@ void ocelot_init_port(struct ocelot *ocelot, int port) REW_PORT_VLAN_CFG_PORT_TPID_M, REW_PORT_VLAN_CFG, port); + /* Disable source address learning for standalone mode */ + ocelot_port_set_learning(ocelot, port, false); + /* Enable vcap lookups */ ocelot_vcap_enable(ocelot, port); } diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c index f9da4aa39444..b5ffe6724eb7 100644 --- a/drivers/net/ethernet/mscc/ocelot_net.c +++ b/drivers/net/ethernet/mscc/ocelot_net.c @@ -1026,6 +1026,13 @@ static int ocelot_port_attr_set(struct net_device *dev, case SWITCHDEV_ATTR_ID_BRIDGE_MC_DISABLED: ocelot_port_attr_mc_set(ocelot, port, !attr->u.mc_disabled); break; + case SWITCHDEV_ATTR_ID_PORT_PRE_BRIDGE_FLAGS: + err = ocelot_port_pre_bridge_flags(ocelot, port, + attr->u.brport_flags); + break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + ocelot_port_bridge_flags(ocelot, port, attr->u.brport_flags); + break; default: err = -EOPNOTSUPP; break; @@ -1111,6 +1118,40 @@ static int ocelot_port_obj_del(struct net_device *dev, return ret; } +static int ocelot_netdevice_bridge_join(struct ocelot *ocelot, int port, + struct net_device *bridge) +{ + struct switchdev_brport_flags flags; + int err; + + flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; + flags.val = flags.mask; + + err = ocelot_port_bridge_join(ocelot, port, bridge); + if (err) + return err; + + ocelot_port_bridge_flags(ocelot, port, flags); + + return 0; +} + +static int ocelot_netdevice_bridge_leave(struct ocelot *ocelot, int port, + struct net_device *bridge) +{ + struct switchdev_brport_flags flags; + int err; + + flags.mask = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD; + flags.val = flags.mask & ~BR_LEARNING; + + err = ocelot_port_bridge_leave(ocelot, port, bridge); + + ocelot_port_bridge_flags(ocelot, port, flags); + + return err; +} + static int ocelot_netdevice_changeupper(struct net_device *dev, struct netdev_notifier_changeupper_info *info) { @@ -1122,11 +1163,11 @@ static int ocelot_netdevice_changeupper(struct net_device *dev, if (netif_is_bridge_master(info->upper_dev)) { if (info->linking) { - err = ocelot_port_bridge_join(ocelot, port, - info->upper_dev); + err = ocelot_netdevice_bridge_join(ocelot, port, + info->upper_dev); } else { - err = ocelot_port_bridge_leave(ocelot, port, - info->upper_dev); + err = ocelot_netdevice_bridge_leave(ocelot, port, + info->upper_dev); } } if (netif_is_lag_master(info->upper_dev)) { diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h index 9acbef1416f1..40792b37bb9f 100644 --- a/include/soc/mscc/ocelot.h +++ b/include/soc/mscc/ocelot.h @@ -612,6 +612,7 @@ struct ocelot_port { u8 *xmit_template; bool is_dsa_8021q_cpu; + bool learn_ena; struct net_device *bond; bool lag_tx_active; @@ -766,6 +767,10 @@ void ocelot_adjust_link(struct ocelot *ocelot, int port, int ocelot_port_vlan_filtering(struct ocelot *ocelot, int port, bool enabled); void ocelot_bridge_stp_state_set(struct ocelot *ocelot, int port, u8 state); void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot); +int ocelot_port_pre_bridge_flags(struct ocelot *ocelot, int port, + struct switchdev_brport_flags val); +void ocelot_port_bridge_flags(struct ocelot *ocelot, int port, + struct switchdev_brport_flags val); int ocelot_port_bridge_join(struct ocelot *ocelot, int port, struct net_device *bridge); int ocelot_port_bridge_leave(struct ocelot *ocelot, int port, From patchwork Fri Feb 12 15:16:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vladimir Oltean X-Patchwork-Id: 382100 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.7 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CD80CC433E9 for ; Fri, 12 Feb 2021 15:18:35 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 764AF64DF2 for ; Fri, 12 Feb 2021 15:18:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232042AbhBLPSF (ORCPT ); Fri, 12 Feb 2021 10:18:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48224 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231768AbhBLPRg (ORCPT ); Fri, 12 Feb 2021 10:17:36 -0500 Received: from mail-ej1-x62d.google.com (mail-ej1-x62d.google.com [IPv6:2a00:1450:4864:20::62d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3E665C061797; Fri, 12 Feb 2021 07:16:25 -0800 (PST) Received: by mail-ej1-x62d.google.com with SMTP id y9so16168179ejp.10; Fri, 12 Feb 2021 07:16:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=P+Brvifs/BkUnWCkXsLQDmXZoYvki80CKh4HAtX6MCc=; b=NVT2fUK/TIjlWmuM+Ph/PFi44Ni40t/7khpCJ+gXDN3zQH005NBJxZiUS8/7CRLcEF kjPJKqyu8jXm1wmcKHi7oYlSOhmMEIP84OMv5nIIevxJn3S5nQv8feg7+fFhxR59fxvf cQH1n2Fbq5eyOBBkDwo5kEOvP07q6sfmiVfxRkshhw3F2idHztMXqOu2bQ3RYHvmof78 20biVl2SVsauzb97KVkhvFeWIzAoeqRTkq3KS3c1jf/iD/xD06bLhAxAnrEDBApYt+oo 00mtkACbp/Cb+JitANcjmEX3D9/rp0IVP1bWJjtc8TJMXTUe0t28w9zKR5q/amaXr2/f GsLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=P+Brvifs/BkUnWCkXsLQDmXZoYvki80CKh4HAtX6MCc=; b=DOT73obzyE62ro9mHpDY8nZwbnv5mCT9x0flyLyiEtkpnKXhZhhEnlJFOLdtDHFD0K 4em8YlUAgkjjk1VMIRYHn6sPR5T5iSQjKvNJsoGcewbao24+OwutnXMntBBau+AvYSE1 giuUvIKuflddBbMPDWo4dEOqTizUN3zkH+zSOBVAgJVCUb+SBcL1M4KGnBDztGqXsTor IWJCNmn+tYHFbST3YdLie2Nx3Hl+bLI3hNz0UaOI6RImiEwOUxTFGs966CGDxoBQh1M+ bapfBrpMEeICS4qG1+6WKwZP1jwM0xjL0msWydZ23H0EqQqES8vUFCa56dCEixuffqNQ 8/FA== X-Gm-Message-State: AOAM533okBgbPcDcFgIvWiA95yhBl7lsV8djlGq2JlnDa8O4C9QhGsMz 4tRb5MayqR62oERHQC5fq4A= X-Google-Smtp-Source: ABdhPJwDlvKB5skkjjju2tH60fHvzvbaeOPkLyd0Vx5aayl0wVva+OY/yrIOCm7xZO0OQE0mN0FXEg== X-Received: by 2002:a17:906:37c1:: with SMTP id o1mr3423062ejc.488.1613142983875; Fri, 12 Feb 2021 07:16:23 -0800 (PST) Received: from localhost.localdomain (5-12-227-87.residential.rdsnet.ro. [5.12.227.87]) by smtp.gmail.com with ESMTPSA id z19sm6515456edr.69.2021.02.12.07.16.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Feb 2021 07:16:23 -0800 (PST) From: Vladimir Oltean To: Jakub Kicinski , "David S. Miller" Cc: Andrew Lunn , Vivien Didelot , Florian Fainelli , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, bridge@lists.linux-foundation.org, Roopa Prabhu , Nikolay Aleksandrov , Jiri Pirko , Ido Schimmel , Claudiu Manoil , Alexandre Belloni , UNGLinuxDriver@microchip.com, Vadym Kochan , Taras Chornyi , Grygorii Strashko , Vignesh Raghavendra , Ioana Ciornei , Ivan Vecera , linux-omap@vger.kernel.org Subject: [PATCH v5 net-next 10/10] net: dsa: sja1105: offload bridge port flags to device Date: Fri, 12 Feb 2021 17:16:00 +0200 Message-Id: <20210212151600.3357121-11-olteanv@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210212151600.3357121-1-olteanv@gmail.com> References: <20210212151600.3357121-1-olteanv@gmail.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Vladimir Oltean The chip can configure unicast flooding, broadcast flooding and learning. Learning is per port, while flooding is per {ingress, egress} port pair and we need to configure the same value for all possible ingress ports towards the requested one. While multicast flooding is not officially supported, we can hack it by using a feature of the second generation (P/Q/R/S) devices, which is that FDB entries are maskable, and multicast addresses always have an odd first octet. So by putting a match-all for 00:01:00:00:00:00 addr and 00:01:00:00:00:00 mask at the end of the FDB, we make sure that it is always checked last, and does not take precedence in front of any other MDB. So it behaves effectively as an unknown multicast entry. For the first generation switches, this feature is not available, so unknown multicast will always be treated the same as unknown unicast. So the only thing we can do is request the user to offload the settings for these 2 flags in tandem, i.e. ip link set swp2 type bridge_slave flood off Error: sja1105: This chip cannot configure multicast flooding independently of unicast. ip link set swp2 type bridge_slave flood off mcast_flood off ip link set swp2 type bridge_slave mcast_flood on Error: sja1105: This chip cannot configure multicast flooding independently of unicast. Signed-off-by: Vladimir Oltean --- Changes in v5: None. Changes in v4: Move the restrictions to .port_pre_bridge_flags. Changes in v3: None. Changes in v2: Patch is new. drivers/net/dsa/sja1105/sja1105.h | 2 + drivers/net/dsa/sja1105/sja1105_main.c | 222 +++++++++++++++++++++++-- drivers/net/dsa/sja1105/sja1105_spi.c | 6 + 3 files changed, 219 insertions(+), 11 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index d582308c2401..15a0893d0ff1 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -94,6 +94,7 @@ struct sja1105_info { * pop it when it's equal to TPID2. */ u16 qinq_tpid; + bool can_limit_mcast_flood; int (*reset_cmd)(struct dsa_switch *ds); int (*setup_rgmii_delay)(const void *ctx, int port); /* Prototypes from include/net/dsa.h */ @@ -204,6 +205,7 @@ struct sja1105_private { bool rgmii_rx_delay[SJA1105_NUM_PORTS]; bool rgmii_tx_delay[SJA1105_NUM_PORTS]; bool best_effort_vlan_filtering; + unsigned long learn_ena; const struct sja1105_info *info; struct gpio_desc *reset_gpio; struct spi_device *spidev; diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index 282253543f3b..1dad94540cc9 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -25,6 +25,8 @@ #include "sja1105_sgmii.h" #include "sja1105_tas.h" +#define SJA1105_UNKNOWN_MULTICAST 0x010000000000ull + static const struct dsa_switch_ops sja1105_switch_ops; static void sja1105_hw_reset(struct gpio_desc *gpio, unsigned int pulse_len, @@ -42,15 +44,10 @@ static void sja1105_port_allow_traffic(struct sja1105_l2_forwarding_entry *l2_fwd, int from, int to, bool allow) { - if (allow) { - l2_fwd[from].bc_domain |= BIT(to); + if (allow) l2_fwd[from].reach_port |= BIT(to); - l2_fwd[from].fl_domain |= BIT(to); - } else { - l2_fwd[from].bc_domain &= ~BIT(to); + else l2_fwd[from].reach_port &= ~BIT(to); - l2_fwd[from].fl_domain &= ~BIT(to); - } } /* Structure used to temporarily transport device tree @@ -220,17 +217,43 @@ static int sja1105_init_mii_settings(struct sja1105_private *priv, static int sja1105_init_static_fdb(struct sja1105_private *priv) { + struct sja1105_l2_lookup_entry *l2_lookup; struct sja1105_table *table; + int port; table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP]; - /* We only populate the FDB table through dynamic - * L2 Address Lookup entries + /* We only populate the FDB table through dynamic L2 Address Lookup + * entries, except for a special entry at the end which is a catch-all + * for unknown multicast and will be used to control flooding domain. */ if (table->entry_count) { kfree(table->entries); table->entry_count = 0; } + + if (!priv->info->can_limit_mcast_flood) + return 0; + + table->entries = kcalloc(1, table->ops->unpacked_entry_size, + GFP_KERNEL); + if (!table->entries) + return -ENOMEM; + + table->entry_count = 1; + l2_lookup = table->entries; + + /* All L2 multicast addresses have an odd first octet */ + l2_lookup[0].macaddr = SJA1105_UNKNOWN_MULTICAST; + l2_lookup[0].mask_macaddr = SJA1105_UNKNOWN_MULTICAST; + l2_lookup[0].lockeds = true; + l2_lookup[0].index = SJA1105_MAX_L2_LOOKUP_COUNT - 1; + + /* Flood multicast to every port by default */ + for (port = 0; port < priv->ds->num_ports; port++) + if (!dsa_is_unused_port(priv->ds, port)) + l2_lookup[0].destports |= BIT(port); + return 0; } @@ -390,6 +413,12 @@ static int sja1105_init_l2_forwarding(struct sja1105_private *priv) sja1105_port_allow_traffic(l2fwd, i, upstream, true); sja1105_port_allow_traffic(l2fwd, upstream, i, true); + + l2fwd[i].bc_domain = BIT(upstream); + l2fwd[i].fl_domain = BIT(upstream); + + l2fwd[upstream].bc_domain |= BIT(i); + l2fwd[upstream].fl_domain |= BIT(i); } /* Next 8 entries define VLAN PCP mapping from ingress to egress. * Create a one-to-one mapping. @@ -1514,6 +1543,12 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port, */ if (!(l2_lookup.destports & BIT(port))) continue; + + /* We need to hide the FDB entry for unknown multicast */ + if (l2_lookup.macaddr == SJA1105_UNKNOWN_MULTICAST && + l2_lookup.mask_macaddr == SJA1105_UNKNOWN_MULTICAST) + continue; + u64_to_ether_addr(l2_lookup.macaddr, macaddr); /* We need to hide the dsa_8021q VLANs from the user. */ @@ -1605,12 +1640,12 @@ static void sja1105_bridge_stp_state_set(struct dsa_switch *ds, int port, case BR_STATE_LEARNING: mac[port].ingress = true; mac[port].egress = false; - mac[port].dyn_learn = true; + mac[port].dyn_learn = !!(priv->learn_ena & BIT(port)); break; case BR_STATE_FORWARDING: mac[port].ingress = true; mac[port].egress = true; - mac[port].dyn_learn = true; + mac[port].dyn_learn = !!(priv->learn_ena & BIT(port)); break; default: dev_err(ds->dev, "invalid STP state: %d\n", state); @@ -3239,6 +3274,169 @@ static void sja1105_port_policer_del(struct dsa_switch *ds, int port) sja1105_static_config_reload(priv, SJA1105_BEST_EFFORT_POLICING); } +static int sja1105_port_set_learning(struct sja1105_private *priv, int port, + bool enabled) +{ + struct sja1105_mac_config_entry *mac; + int rc; + + mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; + + mac[port].dyn_learn = !!(priv->learn_ena & BIT(port)); + + rc = sja1105_dynamic_config_write(priv, BLK_IDX_MAC_CONFIG, port, + &mac[port], true); + if (rc) + return rc; + + if (enabled) + priv->learn_ena |= BIT(port); + else + priv->learn_ena &= ~BIT(port); + + return 0; +} + +/* Common function for unicast and broadcast flood configuration. + * Flooding is configured between each {ingress, egress} port pair, and since + * the bridge's semantics are those of "egress flooding", it means we must + * enable flooding towards this port from all ingress ports that are in the + * same bridge. In practice, we just enable flooding from all possible ingress + * ports regardless of whether they're in the same bridge or not, since the + * reach_port configuration will not allow flooded frames to leak across + * bridging domains anyway. + */ +static int sja1105_port_ucast_bcast_flood(struct sja1105_private *priv, int to, + struct switchdev_brport_flags flags) +{ + struct sja1105_l2_forwarding_entry *l2_fwd; + int from, rc; + + l2_fwd = priv->static_config.tables[BLK_IDX_L2_FORWARDING].entries; + + for (from = 0; from < priv->ds->num_ports; from++) { + if (dsa_is_unused_port(priv->ds, from)) + continue; + if (from == to) + continue; + + /* Unicast */ + if (flags.mask & BR_FLOOD) { + if (flags.val & BR_FLOOD) + l2_fwd[from].fl_domain |= BIT(to); + else + l2_fwd[from].fl_domain &= ~BIT(to); + } + /* Broadcast */ + if (flags.mask & BR_BCAST_FLOOD) { + if (flags.val & BR_BCAST_FLOOD) + l2_fwd[from].bc_domain |= BIT(to); + else + l2_fwd[from].bc_domain &= ~BIT(to); + } + + rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_FORWARDING, + from, &l2_fwd[from], true); + if (rc < 0) + return rc; + } + + return 0; +} + +static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct sja1105_l2_lookup_entry *l2_lookup; + struct sja1105_table *table; + int match; + + table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP]; + l2_lookup = table->entries; + + for (match = 0; match < table->entry_count; match++) + if (l2_lookup[match].macaddr == SJA1105_UNKNOWN_MULTICAST && + l2_lookup[match].mask_macaddr == SJA1105_UNKNOWN_MULTICAST) + break; + + if (match == table->entry_count) { + NL_SET_ERR_MSG_MOD(extack, + "Could not find FDB entry for unknown multicast"); + return -ENOSPC; + } + + if (flags.val & BR_MCAST_FLOOD) + l2_lookup[match].destports |= BIT(to); + else + l2_lookup[match].destports &= ~BIT(to); + + return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP, + l2_lookup[match].index, + &l2_lookup[match], + true); +} + +static int sja1105_port_pre_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct sja1105_private *priv = ds->priv; + + if (flags.mask & ~(BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | + BR_BCAST_FLOOD)) + return -EINVAL; + + if (flags.mask & (BR_FLOOD | BR_MCAST_FLOOD) && + !priv->info->can_limit_mcast_flood) { + bool multicast = !!(flags.val & BR_MCAST_FLOOD); + bool unicast = !!(flags.val & BR_FLOOD); + + if (unicast != multicast) { + NL_SET_ERR_MSG_MOD(extack, + "This chip cannot configure multicast flooding independently of unicast"); + return -EINVAL; + } + } + + return 0; +} + +static int sja1105_port_bridge_flags(struct dsa_switch *ds, int port, + struct switchdev_brport_flags flags, + struct netlink_ext_ack *extack) +{ + struct sja1105_private *priv = ds->priv; + int rc; + + if (flags.mask & BR_LEARNING) { + bool learn_ena = !!(flags.val & BR_LEARNING); + + rc = sja1105_port_set_learning(priv, port, learn_ena); + if (rc) + return rc; + } + + if (flags.mask & (BR_FLOOD | BR_BCAST_FLOOD)) { + rc = sja1105_port_ucast_bcast_flood(priv, port, flags); + if (rc) + return rc; + } + + /* For chips that can't offload BR_MCAST_FLOOD independently, there + * is nothing to do here, we ensured the configuration is in sync by + * offloading BR_FLOOD. + */ + if (flags.mask & BR_MCAST_FLOOD && priv->info->can_limit_mcast_flood) { + rc = sja1105_port_mcast_flood(priv, port, flags, + extack); + if (rc) + return rc; + } + + return 0; +} + static const struct dsa_switch_ops sja1105_switch_ops = { .get_tag_protocol = sja1105_get_tag_protocol, .setup = sja1105_setup, @@ -3262,6 +3460,8 @@ static const struct dsa_switch_ops sja1105_switch_ops = { .port_fdb_del = sja1105_fdb_del, .port_bridge_join = sja1105_bridge_join, .port_bridge_leave = sja1105_bridge_leave, + .port_pre_bridge_flags = sja1105_port_pre_bridge_flags, + .port_bridge_flags = sja1105_port_bridge_flags, .port_stp_state_set = sja1105_bridge_stp_state_set, .port_vlan_filtering = sja1105_vlan_filtering, .port_vlan_add = sja1105_vlan_add, diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 591c5734747d..f7a1514f81e8 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -512,6 +512,7 @@ const struct sja1105_info sja1105e_info = { .static_ops = sja1105e_table_ops, .dyn_ops = sja1105et_dyn_ops, .qinq_tpid = ETH_P_8021Q, + .can_limit_mcast_flood = false, .ptp_ts_bits = 24, .ptpegr_ts_bytes = 4, .num_cbs_shapers = SJA1105ET_MAX_CBS_COUNT, @@ -529,6 +530,7 @@ const struct sja1105_info sja1105t_info = { .static_ops = sja1105t_table_ops, .dyn_ops = sja1105et_dyn_ops, .qinq_tpid = ETH_P_8021Q, + .can_limit_mcast_flood = false, .ptp_ts_bits = 24, .ptpegr_ts_bytes = 4, .num_cbs_shapers = SJA1105ET_MAX_CBS_COUNT, @@ -546,6 +548,7 @@ const struct sja1105_info sja1105p_info = { .static_ops = sja1105p_table_ops, .dyn_ops = sja1105pqrs_dyn_ops, .qinq_tpid = ETH_P_8021AD, + .can_limit_mcast_flood = true, .ptp_ts_bits = 32, .ptpegr_ts_bytes = 8, .num_cbs_shapers = SJA1105PQRS_MAX_CBS_COUNT, @@ -564,6 +567,7 @@ const struct sja1105_info sja1105q_info = { .static_ops = sja1105q_table_ops, .dyn_ops = sja1105pqrs_dyn_ops, .qinq_tpid = ETH_P_8021AD, + .can_limit_mcast_flood = true, .ptp_ts_bits = 32, .ptpegr_ts_bytes = 8, .num_cbs_shapers = SJA1105PQRS_MAX_CBS_COUNT, @@ -582,6 +586,7 @@ const struct sja1105_info sja1105r_info = { .static_ops = sja1105r_table_ops, .dyn_ops = sja1105pqrs_dyn_ops, .qinq_tpid = ETH_P_8021AD, + .can_limit_mcast_flood = true, .ptp_ts_bits = 32, .ptpegr_ts_bytes = 8, .num_cbs_shapers = SJA1105PQRS_MAX_CBS_COUNT, @@ -601,6 +606,7 @@ const struct sja1105_info sja1105s_info = { .dyn_ops = sja1105pqrs_dyn_ops, .regs = &sja1105pqrs_regs, .qinq_tpid = ETH_P_8021AD, + .can_limit_mcast_flood = true, .ptp_ts_bits = 32, .ptpegr_ts_bytes = 8, .num_cbs_shapers = SJA1105PQRS_MAX_CBS_COUNT,