cxgb4 : retrieve port information from firmware
authorGanesh Goudar <ganeshgr@chelsio.com>
Fri, 19 May 2017 12:20:15 +0000 (17:50 +0530)
committerDavid S. Miller <davem@davemloft.net>
Sun, 21 May 2017 17:30:29 +0000 (13:30 -0400)
issue get port information command to firmware to retrieve port
information and update if it is different from what was last
recorded and also add indication for supported link modes for
firmware port types FW_PORT_TYPE_SFP28, FW_PORT_TYPE_KR_SFP28,
FW_PORT_TYPE_CR4_QSFP.

Based on the original work by Casey Leedom <leedom@chelsio.com>

Signed-off-by: Casey Leedom <leedom@chelsio.com>
Signed-off-by: Ganesh Goudar <ganeshgr@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h

index e88c1808e46f06e77671224d3a6a5edeb18ebc0d..1cf3e2f89fc1e6cc90eca24a7e8a6712a32561ce 100644 (file)
@@ -1551,6 +1551,7 @@ int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf,
                    unsigned int vf, unsigned int eqid);
 int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
 void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl);
+int t4_update_port_info(struct port_info *pi);
 int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
 void t4_db_full(struct adapter *adapter);
 void t4_db_dropped(struct adapter *adapter);
index 0ba7866c82598a5b4c2f719cfa4944c46081c04c..e9bab72253bb9bcfd9e9bfdc6e4b761d59125bda 100644 (file)
@@ -500,7 +500,11 @@ static int from_fw_port_mod_type(enum fw_port_type port_type,
        } else if (port_type == FW_PORT_TYPE_SFP ||
                   port_type == FW_PORT_TYPE_QSFP_10G ||
                   port_type == FW_PORT_TYPE_QSA ||
-                  port_type == FW_PORT_TYPE_QSFP) {
+                  port_type == FW_PORT_TYPE_QSFP ||
+                  port_type == FW_PORT_TYPE_CR4_QSFP ||
+                  port_type == FW_PORT_TYPE_CR_QSFP ||
+                  port_type == FW_PORT_TYPE_CR2_QSFP ||
+                  port_type == FW_PORT_TYPE_SFP28) {
                if (mod_type == FW_PORT_MOD_TYPE_LR ||
                    mod_type == FW_PORT_MOD_TYPE_SR ||
                    mod_type == FW_PORT_MOD_TYPE_ER ||
@@ -511,6 +515,9 @@ static int from_fw_port_mod_type(enum fw_port_type port_type,
                        return PORT_DA;
                else
                        return PORT_OTHER;
+       } else if (port_type == FW_PORT_TYPE_KR4_100G ||
+                  port_type == FW_PORT_TYPE_KR_SFP28) {
+               return PORT_NONE;
        }
 
        return PORT_OTHER;
@@ -618,7 +625,21 @@ static void fw_caps_to_lmm(enum fw_port_type port_type,
        case FW_PORT_TYPE_CR_QSFP:
        case FW_PORT_TYPE_SFP28:
                SET_LMM(FIBRE);
-               SET_LMM(25000baseCR_Full);
+               FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full);
+               FW_CAPS_TO_LMM(SPEED_10G, 10000baseT_Full);
+               FW_CAPS_TO_LMM(SPEED_25G, 25000baseCR_Full);
+               break;
+
+       case FW_PORT_TYPE_KR_SFP28:
+               SET_LMM(Backplane);
+               FW_CAPS_TO_LMM(SPEED_1G, 1000baseT_Full);
+               FW_CAPS_TO_LMM(SPEED_10G, 10000baseKR_Full);
+               FW_CAPS_TO_LMM(SPEED_25G, 25000baseKR_Full);
+               break;
+
+       case FW_PORT_TYPE_CR2_QSFP:
+               SET_LMM(FIBRE);
+               SET_LMM(50000baseSR2_Full);
                break;
 
        case FW_PORT_TYPE_KR4_100G:
@@ -674,13 +695,20 @@ static unsigned int lmm_to_fw_caps(const unsigned long *link_mode_mask)
 static int get_link_ksettings(struct net_device *dev,
                              struct ethtool_link_ksettings *link_ksettings)
 {
-       const struct port_info *pi = netdev_priv(dev);
+       struct port_info *pi = netdev_priv(dev);
        struct ethtool_link_settings *base = &link_ksettings->base;
 
        ethtool_link_ksettings_zero_link_mode(link_ksettings, supported);
        ethtool_link_ksettings_zero_link_mode(link_ksettings, advertising);
        ethtool_link_ksettings_zero_link_mode(link_ksettings, lp_advertising);
 
+       /* For the nonce, the Firmware doesn't send up Port State changes
+        * when the Virtual Interface attached to the Port is down.  So
+        * if it's down, let's grab any changes.
+        */
+       if (!netif_running(dev))
+               (void)t4_update_port_info(pi);
+
        base->port = from_fw_port_mod_type(pi->port_type, pi->mod_type);
 
        if (pi->mdio_addr >= 0) {
index 4249ffbc0427e81879a7ea0db2e39196c19279c5..2ae54d54aea8ff9ec0cdb85015e92f31d42e07bd 100644 (file)
@@ -2245,6 +2245,13 @@ static int cxgb_open(struct net_device *dev)
                        return err;
        }
 
+       /* It's possible that the basic port information could have
+        * changed since we first read it.
+        */
+       err = t4_update_port_info(pi);
+       if (err < 0)
+               return err;
+
        err = link_start(dev);
        if (!err)
                netif_tx_start_all_queues(dev);
index aded42b96f6d966ba7e814c0a89c738968a655b6..b97ce4a15ae033f4411e5594c26f622481499687 100644 (file)
@@ -7355,10 +7355,40 @@ void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl)
                lc->fc = fc;
                lc->supported = be16_to_cpu(p->u.info.pcap);
                lc->lp_advertising = be16_to_cpu(p->u.info.lpacap);
+
                t4_os_link_changed(adap, pi->port_id, link_ok);
        }
 }
 
+/**
+ *     t4_update_port_info - retrieve and update port information if changed
+ *     @pi: the port_info
+ *
+ *     We issue a Get Port Information Command to the Firmware and, if
+ *     successful, we check to see if anything is different from what we
+ *     last recorded and update things accordingly.
+ */
+int t4_update_port_info(struct port_info *pi)
+{
+       struct fw_port_cmd port_cmd;
+       int ret;
+
+       memset(&port_cmd, 0, sizeof(port_cmd));
+       port_cmd.op_to_portid = cpu_to_be32(FW_CMD_OP_V(FW_PORT_CMD) |
+                                           FW_CMD_REQUEST_F | FW_CMD_READ_F |
+                                           FW_PORT_CMD_PORTID_V(pi->port_id));
+       port_cmd.action_to_len16 = cpu_to_be32(
+               FW_PORT_CMD_ACTION_V(FW_PORT_ACTION_GET_PORT_INFO) |
+               FW_LEN16(port_cmd));
+       ret = t4_wr_mbox(pi->adapter, pi->adapter->mbox,
+                        &port_cmd, sizeof(port_cmd), &port_cmd);
+       if (ret)
+               return ret;
+
+       t4_handle_get_port_info(pi, (__be64 *)&port_cmd);
+       return 0;
+}
+
 /**
  *      t4_handle_fw_rpl - process a FW reply message
  *      @adap: the adapter
index 251a35e9795c56e943fce354f26b45bcddae8d1c..c65c33c03bcbba027ad32af7bc20c5f8d8412fd8 100644 (file)
@@ -2572,6 +2572,7 @@ enum fw_port_type {
        FW_PORT_TYPE_CR_QSFP,
        FW_PORT_TYPE_CR2_QSFP,
        FW_PORT_TYPE_SFP28,
+       FW_PORT_TYPE_KR_SFP28,
 
        FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_M
 };