Forcing link up of virtual interfaces even when physical link is down
causes packet drops and ping failures during bonding failover. Hence
adding a ethtool private flag to toggle force_link_up whenever required.

Signed-off-by: Arjun Vynipadath <ar...@chelsio.com>
Signed-off-by: Casey Leedom <lee...@chelsio.com>
Signed-off-by: Ganesh Goudar <ganes...@chelsio.com>
---
 drivers/net/ethernet/chelsio/cxgb4vf/adapter.h     | 16 +++++++
 .../net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c    | 54 +++++++++++++++++++++-
 2 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h 
b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
index 5883f09..444a5c8 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/adapter.h
@@ -78,6 +78,18 @@ enum {
        MAX_EGRQ        = MAX_ETH_QSETS*2,
 };
 
+enum {
+       PRIV_FLAG_PORT_FORCE_LINKUP_BIT,
+};
+
+#define PRIV_FLAG_PORT_FORCE_LINKUP    \
+                               BIT(PRIV_FLAG_PORT_FORCE_LINKUP_BIT)
+
+#define PRIV_FLAGS_ADAP                0x0
+#define DEFAULT_PRIV_FLAGS_ADAP        0x0
+#define PRIV_FLAGS_PORT                PRIV_FLAG_PORT_FORCE_LINKUP
+#define DEFAULT_PRIV_FLAGS_PORT        PRIV_FLAG_PORT_FORCE_LINKUP
+
 /*
  * Forward structure definition references.
  */
@@ -103,6 +115,7 @@ struct port_info {
        u8 port_id;                     /* physical port ID */
        u8 nqsets;                      /* # of "Queue Sets" */
        u8 first_qset;                  /* index of first "Queue Set" */
+       u32 eth_flags;                  /* ethtool private flags */
        struct link_config link_cfg;    /* physical port configuration */
 };
 
@@ -374,6 +387,9 @@ struct adapter {
        unsigned long flags;
        struct adapter_params params;
 
+       /* ethtool private flags */
+       u32 eth_flags;
+
        /* queue and interrupt resources */
        struct {
                unsigned short vec;
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c 
b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index ff84791..ac10b5b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -138,6 +138,7 @@ static struct dentry *cxgb4vf_debugfs_root;
 void t4vf_os_link_changed(struct adapter *adapter, int pidx, int link_ok)
 {
        struct net_device *dev = adapter->port[pidx];
+       const struct port_info *pi = netdev_priv(dev);
 
        /*
         * If the port is disabled or the current recorded "link up"
@@ -153,7 +154,9 @@ void t4vf_os_link_changed(struct adapter *adapter, int 
pidx, int link_ok)
        if (link_ok) {
                const char *s;
                const char *fc;
-               const struct port_info *pi = netdev_priv(dev);
+
+               if (!(pi->eth_flags & PRIV_FLAG_PORT_FORCE_LINKUP))
+                       netif_carrier_on(dev);
 
                switch (pi->link_cfg.speed) {
                case 100:
@@ -200,6 +203,8 @@ void t4vf_os_link_changed(struct adapter *adapter, int 
pidx, int link_ok)
 
                netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, fc);
        } else {
+               if (!(pi->eth_flags & PRIV_FLAG_PORT_FORCE_LINKUP))
+                       netif_carrier_off(dev);
                netdev_info(dev, "link down\n");
        }
 }
@@ -283,7 +288,7 @@ static int link_start(struct net_device *dev)
         * no errors in enabling vi.
         */
 
-       if (ret == 0)
+       if (ret == 0 && (pi->eth_flags & PRIV_FLAG_PORT_FORCE_LINKUP))
                netif_carrier_on(dev);
 
        return ret;
@@ -1502,6 +1507,10 @@ static int cxgb4vf_get_fecparam(struct net_device *dev,
        return 0;
 }
 
+static const char cxgb4vf_priv_flags_strings[][ETH_GSTRING_LEN] = {
+       [PRIV_FLAG_PORT_FORCE_LINKUP_BIT] = "port_force_linkup",
+};
+
 /*
  * Return our driver information.
  */
@@ -1524,6 +1533,7 @@ static void cxgb4vf_get_drvinfo(struct net_device *dev,
                 FW_HDR_FW_VER_MINOR_G(adapter->params.dev.tprev),
                 FW_HDR_FW_VER_MICRO_G(adapter->params.dev.tprev),
                 FW_HDR_FW_VER_BUILD_G(adapter->params.dev.tprev));
+       drvinfo->n_priv_flags = ARRAY_SIZE(cxgb4vf_priv_flags_strings);
 }
 
 /*
@@ -1728,6 +1738,8 @@ static int cxgb4vf_get_sset_count(struct net_device *dev, 
int sset)
        switch (sset) {
        case ETH_SS_STATS:
                return ARRAY_SIZE(stats_strings);
+       case ETH_SS_PRIV_FLAGS:
+               return ARRAY_SIZE(cxgb4vf_priv_flags_strings);
        default:
                return -EOPNOTSUPP;
        }
@@ -1745,6 +1757,10 @@ static void cxgb4vf_get_strings(struct net_device *dev,
        case ETH_SS_STATS:
                memcpy(data, stats_strings, sizeof(stats_strings));
                break;
+       case ETH_SS_PRIV_FLAGS:
+               memcpy(data, cxgb4vf_priv_flags_strings,
+                      sizeof(cxgb4vf_priv_flags_strings));
+               break;
        }
 }
 
@@ -1868,6 +1884,36 @@ static void cxgb4vf_get_wol(struct net_device *dev,
        memset(&wol->sopass, 0, sizeof(wol->sopass));
 }
 
+static u32 cxgb4vf_get_priv_flags(struct net_device *netdev)
+{
+       struct port_info *pi = netdev_priv(netdev);
+       struct adapter *adapter = pi->adapter;
+
+       return (adapter->eth_flags | pi->eth_flags);
+}
+
+/**
+ *     set_flags - set/unset specified flags if passed in new_flags
+ *     @cur_flags: pointer to current flags
+ *     @new_flags: new incoming flags
+ *     @flags: set of flags to set/unset
+ */
+static inline void set_flags(u32 *cur_flags, u32 new_flags, u32 flags)
+{
+       *cur_flags = (*cur_flags & ~flags) | (new_flags & flags);
+}
+
+static int cxgb4vf_set_priv_flags(struct net_device *netdev, u32 flags)
+{
+       struct port_info *pi = netdev_priv(netdev);
+       struct adapter *adapter = pi->adapter;
+
+       set_flags(&adapter->eth_flags, flags, PRIV_FLAGS_ADAP);
+       set_flags(&pi->eth_flags, flags, PRIV_FLAGS_PORT);
+
+       return 0;
+}
+
 /*
  * TCP Segmentation Offload flags which we support.
  */
@@ -1892,6 +1938,8 @@ static const struct ethtool_ops cxgb4vf_ethtool_ops = {
        .get_regs_len           = cxgb4vf_get_regs_len,
        .get_regs               = cxgb4vf_get_regs,
        .get_wol                = cxgb4vf_get_wol,
+       .get_priv_flags         = cxgb4vf_get_priv_flags,
+       .set_priv_flags         = cxgb4vf_set_priv_flags,
 };
 
 /*
@@ -3138,6 +3186,7 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
                        dev_info(&pdev->dev,
                                 "Using assigned MAC ACL: %pM\n", mac);
                }
+               pi->eth_flags = DEFAULT_PRIV_FLAGS_PORT;
        }
 
        /* See what interrupts we'll be using.  If we've been configured to
@@ -3168,6 +3217,7 @@ static int cxgb4vf_pci_probe(struct pci_dev *pdev,
                }
                adapter->flags |= USING_MSI;
        }
+       adapter->eth_flags = DEFAULT_PRIV_FLAGS_ADAP;
 
        /* Now that we know how many "ports" we have and what interrupt
         * mechanism we're going to use, we can configure our queue resources.
-- 
2.3.5

Reply via email to