Add ops to set link up and down for both PF and VF. If wait_to_complete
is set, poll for link update for up to 10 seconds max.

Original work by Surendra Mobiya <suren...@chelsio.com>

Signed-off-by: Rahul Lakkireddy <rahul.lakkire...@chelsio.com>
---
 drivers/net/cxgbe/cxgbe.h          |  5 +++
 drivers/net/cxgbe/cxgbe_ethdev.c   | 72 ++++++++++++++++++++++++++++++++++++--
 drivers/net/cxgbe/cxgbe_main.c     | 36 +++++++++++++------
 drivers/net/cxgbe/cxgbe_pfvf.h     |  2 ++
 drivers/net/cxgbe/cxgbevf_ethdev.c |  2 ++
 5 files changed, 103 insertions(+), 14 deletions(-)

diff --git a/drivers/net/cxgbe/cxgbe.h b/drivers/net/cxgbe/cxgbe.h
index 27d6e2b84..96a6a4084 100644
--- a/drivers/net/cxgbe/cxgbe.h
+++ b/drivers/net/cxgbe/cxgbe.h
@@ -18,6 +18,10 @@
 #define CXGBE_MIN_RX_BUFSIZE ETHER_MIN_MTU /* min buf size */
 #define CXGBE_MAX_RX_PKTLEN (9000 + ETHER_HDR_LEN + ETHER_CRC_LEN) /* max pkt 
*/
 
+/* Max poll time is 100 * 100msec = 10 sec */
+#define CXGBE_LINK_STATUS_POLL_MS 100 /* 100ms */
+#define CXGBE_LINK_STATUS_POLL_CNT 100 /* Max number of times to poll */
+
 #define CXGBE_DEFAULT_RSS_KEY_LEN     40 /* 320-bits */
 #define CXGBE_RSS_HF_ALL (ETH_RSS_IPV4 | ETH_RSS_IPV6 | \
                          ETH_RSS_NONFRAG_IPV4_TCP | \
@@ -32,6 +36,7 @@ bool force_linkup(struct adapter *adap);
 int cxgbe_probe(struct adapter *adapter);
 int cxgbevf_probe(struct adapter *adapter);
 void cxgbe_get_speed_caps(struct port_info *pi, u32 *speed_caps);
+int cxgbe_set_link_status(struct port_info *pi, bool status);
 int cxgbe_up(struct adapter *adap);
 int cxgbe_down(struct port_info *pi);
 void cxgbe_close(struct adapter *adapter);
diff --git a/drivers/net/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 713dc8fae..eb07a1f89 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -200,15 +200,27 @@ void cxgbe_dev_allmulticast_disable(struct rte_eth_dev 
*eth_dev)
 }
 
 int cxgbe_dev_link_update(struct rte_eth_dev *eth_dev,
-                         __rte_unused int wait_to_complete)
+                         int wait_to_complete)
 {
        struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private);
        struct adapter *adapter = pi->adapter;
        struct sge *s = &adapter->sge;
        struct rte_eth_link new_link = { 0 };
-       unsigned int work_done, budget = 4;
+       unsigned int i, work_done, budget = 32;
+       u8 old_link = pi->link_cfg.link_ok;
 
-       cxgbe_poll(&s->fw_evtq, NULL, budget, &work_done);
+       for (i = 0; i < CXGBE_LINK_STATUS_POLL_CNT; i++) {
+               cxgbe_poll(&s->fw_evtq, NULL, budget, &work_done);
+
+               /* Exit if link status changed or always forced up */
+               if (pi->link_cfg.link_ok != old_link || force_linkup(adapter))
+                       break;
+
+               if (!wait_to_complete)
+                       break;
+
+               rte_delay_ms(CXGBE_LINK_STATUS_POLL_MS);
+       }
 
        new_link.link_status = force_linkup(adapter) ?
                               ETH_LINK_UP : pi->link_cfg.link_ok;
@@ -219,6 +231,58 @@ int cxgbe_dev_link_update(struct rte_eth_dev *eth_dev,
        return rte_eth_linkstatus_set(eth_dev, &new_link);
 }
 
+/**
+ * Set device link up.
+ */
+int cxgbe_dev_set_link_up(struct rte_eth_dev *dev)
+{
+       struct port_info *pi = (struct port_info *)(dev->data->dev_private);
+       struct adapter *adapter = pi->adapter;
+       unsigned int work_done, budget = 32;
+       struct sge *s = &adapter->sge;
+       int ret;
+
+       /* Flush all link events */
+       cxgbe_poll(&s->fw_evtq, NULL, budget, &work_done);
+
+       /* If link already up, nothing to do */
+       if (pi->link_cfg.link_ok)
+               return 0;
+
+       ret = cxgbe_set_link_status(pi, true);
+       if (ret)
+               return ret;
+
+       cxgbe_dev_link_update(dev, 1);
+       return 0;
+}
+
+/**
+ * Set device link down.
+ */
+int cxgbe_dev_set_link_down(struct rte_eth_dev *dev)
+{
+       struct port_info *pi = (struct port_info *)(dev->data->dev_private);
+       struct adapter *adapter = pi->adapter;
+       unsigned int work_done, budget = 32;
+       struct sge *s = &adapter->sge;
+       int ret;
+
+       /* Flush all link events */
+       cxgbe_poll(&s->fw_evtq, NULL, budget, &work_done);
+
+       /* If link already down, nothing to do */
+       if (!pi->link_cfg.link_ok)
+               return 0;
+
+       ret = cxgbe_set_link_status(pi, false);
+       if (ret)
+               return ret;
+
+       cxgbe_dev_link_update(dev, 0);
+       return 0;
+}
+
 int cxgbe_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t mtu)
 {
        struct port_info *pi = (struct port_info *)(eth_dev->data->dev_private);
@@ -1031,6 +1095,8 @@ static const struct eth_dev_ops cxgbe_eth_dev_ops = {
        .dev_infos_get          = cxgbe_dev_info_get,
        .dev_supported_ptypes_get = cxgbe_dev_supported_ptypes_get,
        .link_update            = cxgbe_dev_link_update,
+       .dev_set_link_up        = cxgbe_dev_set_link_up,
+       .dev_set_link_down      = cxgbe_dev_set_link_down,
        .mtu_set                = cxgbe_dev_mtu_set,
        .tx_queue_setup         = cxgbe_dev_tx_queue_setup,
        .tx_queue_start         = cxgbe_dev_tx_queue_start,
diff --git a/drivers/net/cxgbe/cxgbe_main.c b/drivers/net/cxgbe/cxgbe_main.c
index 21ad380ae..edbb4df28 100644
--- a/drivers/net/cxgbe/cxgbe_main.c
+++ b/drivers/net/cxgbe/cxgbe_main.c
@@ -1434,6 +1434,30 @@ void cxgbe_get_speed_caps(struct port_info *pi, u32 
*speed_caps)
                *speed_caps |= ETH_LINK_SPEED_FIXED;
 }
 
+/**
+ * cxgbe_set_link_status - Set device link up or down.
+ * @pi: Underlying port's info
+ * @status: 0 - down, 1 - up
+ *
+ * Set the device link up or down.
+ */
+int cxgbe_set_link_status(struct port_info *pi, bool status)
+{
+       struct adapter *adapter = pi->adapter;
+       int err = 0;
+
+       err = t4_enable_vi(adapter, adapter->mbox, pi->viid, status, status);
+       if (err) {
+               dev_err(adapter, "%s: disable_vi failed: %d\n", __func__, err);
+               return err;
+       }
+
+       if (!status)
+               t4_reset_link_config(adapter, pi->pidx);
+
+       return 0;
+}
+
 /**
  * cxgb_up - enable the adapter
  * @adap: adapter being enabled
@@ -1459,17 +1483,7 @@ int cxgbe_up(struct adapter *adap)
  */
 int cxgbe_down(struct port_info *pi)
 {
-       struct adapter *adapter = pi->adapter;
-       int err = 0;
-
-       err = t4_enable_vi(adapter, adapter->mbox, pi->viid, false, false);
-       if (err) {
-               dev_err(adapter, "%s: disable_vi failed: %d\n", __func__, err);
-               return err;
-       }
-
-       t4_reset_link_config(adapter, pi->pidx);
-       return 0;
+       return cxgbe_set_link_status(pi, false);
 }
 
 /*
diff --git a/drivers/net/cxgbe/cxgbe_pfvf.h b/drivers/net/cxgbe/cxgbe_pfvf.h
index 2bba97423..8d0a105aa 100644
--- a/drivers/net/cxgbe/cxgbe_pfvf.h
+++ b/drivers/net/cxgbe/cxgbe_pfvf.h
@@ -35,6 +35,8 @@ int cxgbe_dev_mtu_set(struct rte_eth_dev *eth_dev, uint16_t 
mtu);
 int cxgbe_dev_start(struct rte_eth_dev *eth_dev);
 int cxgbe_dev_link_update(struct rte_eth_dev *eth_dev,
                          int wait_to_complete);
+int cxgbe_dev_set_link_up(struct rte_eth_dev *dev);
+int cxgbe_dev_set_link_down(struct rte_eth_dev *dev);
 uint16_t cxgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                         uint16_t nb_pkts);
 uint16_t cxgbe_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
diff --git a/drivers/net/cxgbe/cxgbevf_ethdev.c 
b/drivers/net/cxgbe/cxgbevf_ethdev.c
index a942ba6b6..b4770e0c5 100644
--- a/drivers/net/cxgbe/cxgbevf_ethdev.c
+++ b/drivers/net/cxgbe/cxgbevf_ethdev.c
@@ -85,6 +85,8 @@ static const struct eth_dev_ops cxgbevf_eth_dev_ops = {
        .dev_infos_get          = cxgbe_dev_info_get,
        .dev_supported_ptypes_get = cxgbe_dev_supported_ptypes_get,
        .link_update            = cxgbe_dev_link_update,
+       .dev_set_link_up        = cxgbe_dev_set_link_up,
+       .dev_set_link_down      = cxgbe_dev_set_link_down,
        .mtu_set                = cxgbe_dev_mtu_set,
        .tx_queue_setup         = cxgbe_dev_tx_queue_setup,
        .tx_queue_start         = cxgbe_dev_tx_queue_start,
-- 
2.14.1

Reply via email to