be2net: fix port-type reporting in get_settings
authorRavikumar Nelavelli <ravikumar.nelavelli@emulex.com>
Fri, 12 Sep 2014 12:09:19 +0000 (17:39 +0530)
committerDavid S. Miller <davem@davemloft.net>
Sat, 13 Sep 2014 21:12:15 +0000 (17:12 -0400)
Report the ethtool port-type/supported/advertising values based on the
cable_type for QSFP and SFP+ interfaces. The cable_type is parsed from
the transceiver data fetched from the FW.

Signed-off-by: Ravikumar Nelavelli <ravikumar.nelavelli@emulex.com>
Signed-off-by: Suresh Reddy <Suresh.Reddy@emulex.com>
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/emulex/benet/be.h
drivers/net/ethernet/emulex/benet/be_cmds.c
drivers/net/ethernet/emulex/benet/be_cmds.h
drivers/net/ethernet/emulex/benet/be_ethtool.c

index a9f239adc3e3a7db481026e31367281ce6d1e6f5..9a2d75235e89991bd62a7decd437707ce6b78b4b 100644 (file)
@@ -407,9 +407,9 @@ struct phy_info {
        u16 auto_speeds_supported;
        u16 fixed_speeds_supported;
        int link_speed;
-       u32 dac_cable_len;
        u32 advertising;
        u32 supported;
+       u8 cable_type;
 };
 
 struct be_resources {
index e0dd482e22922eb983a8a9bd17418cb1ce513547..85edde6603fe6d8a4e3e5fe2a227b81807714e89 100644 (file)
@@ -2296,6 +2296,31 @@ err_unlock:
        return status;
 }
 
+int be_cmd_query_cable_type(struct be_adapter *adapter)
+{
+       u8 page_data[PAGE_DATA_LEN];
+       int status;
+
+       status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
+                                                  page_data);
+       if (!status) {
+               switch (adapter->phy.interface_type) {
+               case PHY_TYPE_QSFP:
+                       adapter->phy.cable_type =
+                               page_data[QSFP_PLUS_CABLE_TYPE_OFFSET];
+                       break;
+               case PHY_TYPE_SFP_PLUS_10GB:
+                       adapter->phy.cable_type =
+                               page_data[SFP_PLUS_CABLE_TYPE_OFFSET];
+                       break;
+               default:
+                       adapter->phy.cable_type = 0;
+                       break;
+               }
+       }
+       return status;
+}
+
 int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name)
 {
        struct lancer_cmd_req_delete_object *req;
index f05f1fb6e698c5232e250aace8350f3eb034604f..e86a5ef439dd4772a2df9d593b867fd915e0c737 100644 (file)
@@ -1014,8 +1014,16 @@ enum {
        TR_PAGE_A2 = 0xa2
 };
 
+/* From SFF-8436 QSFP+ spec */
+#define        QSFP_PLUS_CABLE_TYPE_OFFSET     0x83
+#define        QSFP_PLUS_CR4_CABLE             0x8
+#define        QSFP_PLUS_SR4_CABLE             0x4
+#define        QSFP_PLUS_LR4_CABLE             0x2
+
 /* From SFF-8472 spec */
-#define        SFP_PLUS_SFF_8472_COMP  0x5E
+#define        SFP_PLUS_SFF_8472_COMP          0x5E
+#define        SFP_PLUS_CABLE_TYPE_OFFSET      0x8
+#define        SFP_PLUS_COPPER_CABLE           0x4
 
 #define PAGE_DATA_LEN   256
 struct be_cmd_resp_port_type {
@@ -1355,6 +1363,9 @@ enum {
        PHY_TYPE_BASET_1GB,
        PHY_TYPE_BASEX_1GB,
        PHY_TYPE_SGMII,
+       PHY_TYPE_QSFP,
+       PHY_TYPE_KR4_40GB,
+       PHY_TYPE_KR2_20GB,
        PHY_TYPE_DISABLED = 255
 };
 
@@ -1363,6 +1374,7 @@ enum {
 #define BE_SUPPORTED_SPEED_100MBPS     2
 #define BE_SUPPORTED_SPEED_1GBPS       4
 #define BE_SUPPORTED_SPEED_10GBPS      8
+#define BE_SUPPORTED_SPEED_40GBPS      0x20
 
 #define BE_AN_EN                       0x2
 #define BE_PAUSE_SYM_EN                        0x80
@@ -2056,6 +2068,7 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num,
                            u32 *state);
 int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
                                      u8 page_num, u8 *data);
+int be_cmd_query_cable_type(struct be_adapter *adapter);
 int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
                          u32 flash_oper, u32 flash_opcode, u32 buf_size);
 int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
index a28013f77777ae6bea22d52a7729eb6a6194ecb2..43b559570632dd4133b73035c96b9c41a5f7f25b 100644 (file)
@@ -475,18 +475,27 @@ static int be_get_sset_count(struct net_device *netdev, int stringset)
        }
 }
 
-static u32 be_get_port_type(u32 phy_type, u32 dac_cable_len)
+static u32 be_get_port_type(struct be_adapter *adapter)
 {
        u32 port;
 
-       switch (phy_type) {
+       switch (adapter->phy.interface_type) {
        case PHY_TYPE_BASET_1GB:
        case PHY_TYPE_BASEX_1GB:
        case PHY_TYPE_SGMII:
                port = PORT_TP;
                break;
        case PHY_TYPE_SFP_PLUS_10GB:
-               port = dac_cable_len ? PORT_DA : PORT_FIBRE;
+               if (adapter->phy.cable_type & SFP_PLUS_COPPER_CABLE)
+                       port = PORT_DA;
+               else
+                       port = PORT_FIBRE;
+               break;
+       case PHY_TYPE_QSFP:
+               if (adapter->phy.cable_type & QSFP_PLUS_CR4_CABLE)
+                       port = PORT_DA;
+               else
+                       port = PORT_FIBRE;
                break;
        case PHY_TYPE_XFP_10GB:
        case PHY_TYPE_SFP_1GB:
@@ -502,11 +511,11 @@ static u32 be_get_port_type(u32 phy_type, u32 dac_cable_len)
        return port;
 }
 
-static u32 convert_to_et_setting(u32 if_type, u32 if_speeds)
+static u32 convert_to_et_setting(struct be_adapter *adapter, u32 if_speeds)
 {
        u32 val = 0;
 
-       switch (if_type) {
+       switch (adapter->phy.interface_type) {
        case PHY_TYPE_BASET_1GB:
        case PHY_TYPE_BASEX_1GB:
        case PHY_TYPE_SGMII:
@@ -529,6 +538,20 @@ static u32 convert_to_et_setting(u32 if_type, u32 if_speeds)
                val |= SUPPORTED_Backplane |
                                SUPPORTED_10000baseKR_Full;
                break;
+       case PHY_TYPE_QSFP:
+               if (if_speeds & BE_SUPPORTED_SPEED_40GBPS) {
+                       switch (adapter->phy.cable_type) {
+                       case QSFP_PLUS_CR4_CABLE:
+                               val |= SUPPORTED_40000baseCR4_Full;
+                               break;
+                       case QSFP_PLUS_LR4_CABLE:
+                               val |= SUPPORTED_40000baseLR4_Full;
+                               break;
+                       default:
+                               val |= SUPPORTED_40000baseSR4_Full;
+                               break;
+                       }
+               }
        case PHY_TYPE_SFP_PLUS_10GB:
        case PHY_TYPE_XFP_10GB:
        case PHY_TYPE_SFP_1GB:
@@ -569,8 +592,6 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
        int status;
        u32 auto_speeds;
        u32 fixed_speeds;
-       u32 dac_cable_len;
-       u16 interface_type;
 
        if (adapter->phy.link_speed < 0) {
                status = be_cmd_link_status_query(adapter, &link_speed,
@@ -581,21 +602,19 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
 
                status = be_cmd_get_phy_info(adapter);
                if (!status) {
-                       interface_type = adapter->phy.interface_type;
                        auto_speeds = adapter->phy.auto_speeds_supported;
                        fixed_speeds = adapter->phy.fixed_speeds_supported;
-                       dac_cable_len = adapter->phy.dac_cable_len;
+
+                       be_cmd_query_cable_type(adapter);
 
                        ecmd->supported =
-                               convert_to_et_setting(interface_type,
+                               convert_to_et_setting(adapter,
                                                      auto_speeds |
                                                      fixed_speeds);
                        ecmd->advertising =
-                               convert_to_et_setting(interface_type,
-                                                     auto_speeds);
+                               convert_to_et_setting(adapter, auto_speeds);
 
-                       ecmd->port = be_get_port_type(interface_type,
-                                                     dac_cable_len);
+                       ecmd->port = be_get_port_type(adapter);
 
                        if (adapter->phy.auto_speeds_supported) {
                                ecmd->supported |= SUPPORTED_Autoneg;