bnxt_en: Implement ndo_bridge_{get|set}link methods.
authorMichael Chan <michael.chan@broadcom.com>
Mon, 24 Jul 2017 16:34:22 +0000 (12:34 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 25 Jul 2017 00:29:58 +0000 (17:29 -0700)
To allow users to set the hardware bridging mode to VEB or VEPA.  Only
single function PF can change the bridging mode.

Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnxt/bnxt.c

index ec8a1958ba12169ceb0adf41a5d030b08da93bee..4acaeaf87f188464638e13e0aae7991406b41a04 100644 (file)
@@ -4919,6 +4919,26 @@ static void bnxt_hwrm_resource_free(struct bnxt *bp, bool close_path,
        }
 }
 
+static int bnxt_hwrm_set_br_mode(struct bnxt *bp, u16 br_mode)
+{
+       struct hwrm_func_cfg_input req = {0};
+       int rc;
+
+       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
+       req.fid = cpu_to_le16(0xffff);
+       req.enables = cpu_to_le32(FUNC_CFG_REQ_ENABLES_EVB_MODE);
+       if (br_mode == BRIDGE_MODE_VEB)
+               req.evb_mode = FUNC_CFG_REQ_EVB_MODE_VEB;
+       else if (br_mode == BRIDGE_MODE_VEPA)
+               req.evb_mode = FUNC_CFG_REQ_EVB_MODE_VEPA;
+       else
+               return -EINVAL;
+       rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
+       if (rc)
+               rc = -EIO;
+       return rc;
+}
+
 static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id)
 {
        struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
@@ -7432,6 +7452,51 @@ static void bnxt_udp_tunnel_del(struct net_device *dev,
        schedule_work(&bp->sp_task);
 }
 
+static int bnxt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
+                              struct net_device *dev, u32 filter_mask,
+                              int nlflags)
+{
+       struct bnxt *bp = netdev_priv(dev);
+
+       return ndo_dflt_bridge_getlink(skb, pid, seq, dev, bp->br_mode, 0, 0,
+                                      nlflags, filter_mask, NULL);
+}
+
+static int bnxt_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
+                              u16 flags)
+{
+       struct bnxt *bp = netdev_priv(dev);
+       struct nlattr *attr, *br_spec;
+       int rem, rc = 0;
+
+       if (bp->hwrm_spec_code < 0x10708 || !BNXT_SINGLE_PF(bp))
+               return -EOPNOTSUPP;
+
+       br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
+       if (!br_spec)
+               return -EINVAL;
+
+       nla_for_each_nested(attr, br_spec, rem) {
+               u16 mode;
+
+               if (nla_type(attr) != IFLA_BRIDGE_MODE)
+                       continue;
+
+               if (nla_len(attr) < sizeof(mode))
+                       return -EINVAL;
+
+               mode = nla_get_u16(attr);
+               if (mode == bp->br_mode)
+                       break;
+
+               rc = bnxt_hwrm_set_br_mode(bp, mode);
+               if (!rc)
+                       bp->br_mode = mode;
+               break;
+       }
+       return rc;
+}
+
 static const struct net_device_ops bnxt_netdev_ops = {
        .ndo_open               = bnxt_open,
        .ndo_start_xmit         = bnxt_start_xmit,
@@ -7463,6 +7528,8 @@ static const struct net_device_ops bnxt_netdev_ops = {
        .ndo_udp_tunnel_add     = bnxt_udp_tunnel_add,
        .ndo_udp_tunnel_del     = bnxt_udp_tunnel_del,
        .ndo_xdp                = bnxt_xdp,
+       .ndo_bridge_getlink     = bnxt_bridge_getlink,
+       .ndo_bridge_setlink     = bnxt_bridge_setlink,
 };
 
 static void bnxt_remove_one(struct pci_dev *pdev)