qlcnic: Update Link speed and port type info for 83xx adapter
authorJitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Wed, 27 Aug 2014 16:43:17 +0000 (12:43 -0400)
committerDavid S. Miller <davem@davemloft.net>
Sat, 30 Aug 2014 03:15:36 +0000 (20:15 -0700)
o Update the port type information
o Advertise correct link modes and autonegotiation
o Add support to change link speed

Signed-off-by: Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h

index 476e499..528c651 100644 (file)
@@ -35,6 +35,35 @@ static void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *);
 #define QLC_SKIP_INACTIVE_PCI_REGS     7
 #define QLC_MAX_LEGACY_FUNC_SUPP       8
 
+/* 83xx Module type */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_LRM      0x1 /* 10GBase-LRM */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_LR       0x2 /* 10GBase-LR */
+#define QLC_83XX_MODULE_FIBRE_10GBASE_SR       0x3 /* 10GBase-SR */
+#define QLC_83XX_MODULE_DA_10GE_PASSIVE_CP     0x4 /* 10GE passive
+                                                    * copper(compliant)
+                                                    */
+#define QLC_83XX_MODULE_DA_10GE_ACTIVE_CP      0x5 /* 10GE active limiting
+                                                    * copper(compliant)
+                                                    */
+#define QLC_83XX_MODULE_DA_10GE_LEGACY_CP      0x6 /* 10GE passive copper
+                                                    * (legacy, best effort)
+                                                    */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_SX      0x7 /* 1000Base-SX */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_LX      0x8 /* 1000Base-LX */
+#define QLC_83XX_MODULE_FIBRE_1000BASE_CX      0x9 /* 1000Base-CX */
+#define QLC_83XX_MODULE_TP_1000BASE_T          0xa /* 1000Base-T*/
+#define QLC_83XX_MODULE_DA_1GE_PASSIVE_CP      0xb /* 1GE passive copper
+                                                    * (legacy, best effort)
+                                                    */
+#define QLC_83XX_MODULE_UNKNOWN                        0xf /* Unknown module type */
+
+/* Port types */
+#define QLC_83XX_10_CAPABLE     BIT_8
+#define QLC_83XX_100_CAPABLE    BIT_9
+#define QLC_83XX_1G_CAPABLE     BIT_10
+#define QLC_83XX_10G_CAPABLE    BIT_11
+#define QLC_83XX_AUTONEG_ENABLE         BIT_15
+
 static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl[] = {
        {QLCNIC_CMD_CONFIGURE_IP_ADDR, 6, 1},
        {QLCNIC_CMD_CONFIG_INTRPT, 18, 34},
@@ -667,6 +696,7 @@ void qlcnic_83xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
 
 int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        int status;
 
        status = qlcnic_83xx_get_port_config(adapter);
@@ -674,13 +704,20 @@ int qlcnic_83xx_get_port_info(struct qlcnic_adapter *adapter)
                dev_err(&adapter->pdev->dev,
                        "Get Port Info failed\n");
        } else {
-               if (QLC_83XX_SFP_10G_CAPABLE(adapter->ahw->port_config))
-                       adapter->ahw->port_type = QLCNIC_XGBE;
-               else
-                       adapter->ahw->port_type = QLCNIC_GBE;
 
-               if (QLC_83XX_AUTONEG(adapter->ahw->port_config))
-                       adapter->ahw->link_autoneg = AUTONEG_ENABLE;
+               if (ahw->port_config & QLC_83XX_10G_CAPABLE) {
+                       ahw->port_type = QLCNIC_XGBE;
+               } else if (ahw->port_config & QLC_83XX_10_CAPABLE ||
+                          ahw->port_config & QLC_83XX_100_CAPABLE ||
+                          ahw->port_config & QLC_83XX_1G_CAPABLE) {
+                       ahw->port_type = QLCNIC_GBE;
+               } else {
+                       ahw->port_type = QLCNIC_XGBE;
+               }
+
+               if (QLC_83XX_AUTONEG(ahw->port_config))
+                       ahw->link_autoneg = AUTONEG_ENABLE;
+
        }
        return status;
 }
@@ -3176,22 +3213,33 @@ int qlcnic_83xx_test_link(struct qlcnic_adapter *adapter)
                        break;
                }
                config = cmd.rsp.arg[3];
-               if (QLC_83XX_SFP_PRESENT(config)) {
-                       switch (ahw->module_type) {
-                       case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
-                       case LINKEVENT_MODULE_OPTICAL_SRLR:
-                       case LINKEVENT_MODULE_OPTICAL_LRM:
-                       case LINKEVENT_MODULE_OPTICAL_SFP_1G:
-                               ahw->supported_type = PORT_FIBRE;
-                               break;
-                       case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
-                       case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
-                       case LINKEVENT_MODULE_TWINAX:
-                               ahw->supported_type = PORT_TP;
-                               break;
-                       default:
-                               ahw->supported_type = PORT_OTHER;
-                       }
+               switch (QLC_83XX_SFP_MODULE_TYPE(config)) {
+               case QLC_83XX_MODULE_FIBRE_10GBASE_LRM:
+               case QLC_83XX_MODULE_FIBRE_10GBASE_LR:
+               case QLC_83XX_MODULE_FIBRE_10GBASE_SR:
+                       ahw->supported_type = PORT_FIBRE;
+                       ahw->port_type = QLCNIC_XGBE;
+                       break;
+               case QLC_83XX_MODULE_FIBRE_1000BASE_SX:
+               case QLC_83XX_MODULE_FIBRE_1000BASE_LX:
+               case QLC_83XX_MODULE_FIBRE_1000BASE_CX:
+                       ahw->supported_type = PORT_FIBRE;
+                       ahw->port_type = QLCNIC_GBE;
+                       break;
+               case QLC_83XX_MODULE_TP_1000BASE_T:
+                       ahw->supported_type = PORT_TP;
+                       ahw->port_type = QLCNIC_GBE;
+                       break;
+               case QLC_83XX_MODULE_DA_10GE_PASSIVE_CP:
+               case QLC_83XX_MODULE_DA_10GE_ACTIVE_CP:
+               case QLC_83XX_MODULE_DA_10GE_LEGACY_CP:
+               case QLC_83XX_MODULE_DA_1GE_PASSIVE_CP:
+                       ahw->supported_type = PORT_DA;
+                       ahw->port_type = QLCNIC_XGBE;
+                       break;
+               default:
+                       ahw->supported_type = PORT_OTHER;
+                       ahw->port_type = QLCNIC_XGBE;
                }
                if (config & 1)
                        err = 1;
@@ -3204,9 +3252,9 @@ out:
 int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                             struct ethtool_cmd *ecmd)
 {
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 config = 0;
        int status = 0;
-       struct qlcnic_hardware_context *ahw = adapter->ahw;
 
        if (!test_bit(__QLCNIC_MAINTENANCE_MODE, &adapter->state)) {
                /* Get port configuration info */
@@ -3229,20 +3277,41 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                ecmd->autoneg = AUTONEG_DISABLE;
        }
 
-       if (ahw->port_type == QLCNIC_XGBE) {
-               ecmd->supported = SUPPORTED_10000baseT_Full;
-               ecmd->advertising = ADVERTISED_10000baseT_Full;
+       ecmd->supported = (SUPPORTED_10baseT_Full |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_1000baseT_Full |
+                          SUPPORTED_10000baseT_Full |
+                          SUPPORTED_Autoneg);
+
+       if (ecmd->autoneg == AUTONEG_ENABLE) {
+               if (ahw->port_config & QLC_83XX_10_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_10baseT_Full;
+               if (ahw->port_config & QLC_83XX_100_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_100baseT_Full;
+               if (ahw->port_config & QLC_83XX_1G_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_1000baseT_Full;
+               if (ahw->port_config & QLC_83XX_10G_CAPABLE)
+                       ecmd->advertising |= SUPPORTED_10000baseT_Full;
+               if (ahw->port_config & QLC_83XX_AUTONEG_ENABLE)
+                       ecmd->advertising |= ADVERTISED_Autoneg;
        } else {
-               ecmd->supported = (SUPPORTED_10baseT_Half |
-                                  SUPPORTED_10baseT_Full |
-                                  SUPPORTED_100baseT_Half |
-                                  SUPPORTED_100baseT_Full |
-                                  SUPPORTED_1000baseT_Half |
-                                  SUPPORTED_1000baseT_Full);
-               ecmd->advertising = (ADVERTISED_100baseT_Half |
-                                    ADVERTISED_100baseT_Full |
-                                    ADVERTISED_1000baseT_Half |
-                                    ADVERTISED_1000baseT_Full);
+               switch (ahw->link_speed) {
+               case SPEED_10:
+                       ecmd->advertising = SUPPORTED_10baseT_Full;
+                       break;
+               case SPEED_100:
+                       ecmd->advertising = SUPPORTED_100baseT_Full;
+                       break;
+               case SPEED_1000:
+                       ecmd->advertising = SUPPORTED_1000baseT_Full;
+                       break;
+               case SPEED_10000:
+                       ecmd->advertising = SUPPORTED_10000baseT_Full;
+                       break;
+               default:
+                       break;
+               }
+
        }
 
        switch (ahw->supported_type) {
@@ -3258,6 +3327,12 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
                ecmd->port = PORT_TP;
                ecmd->transceiver = XCVR_INTERNAL;
                break;
+       case PORT_DA:
+               ecmd->supported |= SUPPORTED_FIBRE;
+               ecmd->advertising |= ADVERTISED_FIBRE;
+               ecmd->port = PORT_DA;
+               ecmd->transceiver = XCVR_EXTERNAL;
+               break;
        default:
                ecmd->supported |= SUPPORTED_FIBRE;
                ecmd->advertising |= ADVERTISED_FIBRE;
@@ -3272,35 +3347,60 @@ int qlcnic_83xx_get_settings(struct qlcnic_adapter *adapter,
 int qlcnic_83xx_set_settings(struct qlcnic_adapter *adapter,
                             struct ethtool_cmd *ecmd)
 {
-       int status = 0;
+       struct qlcnic_hardware_context *ahw = adapter->ahw;
        u32 config = adapter->ahw->port_config;
+       int status = 0;
 
-       if (ecmd->autoneg)
-               adapter->ahw->port_config |= BIT_15;
-
-       switch (ethtool_cmd_speed(ecmd)) {
-       case SPEED_10:
-               adapter->ahw->port_config |= BIT_8;
-               break;
-       case SPEED_100:
-               adapter->ahw->port_config |= BIT_9;
-               break;
-       case SPEED_1000:
-               adapter->ahw->port_config |= BIT_10;
-               break;
-       case SPEED_10000:
-               adapter->ahw->port_config |= BIT_11;
-               break;
-       default:
-               return -EINVAL;
+       /* 83xx devices do not support Half duplex */
+       if (ecmd->duplex == DUPLEX_HALF) {
+                       netdev_info(adapter->netdev,
+                                   "Half duplex mode not supported\n");
+                       return -EINVAL;
        }
 
+       if (ecmd->autoneg) {
+               ahw->port_config |= QLC_83XX_AUTONEG_ENABLE;
+               ahw->port_config |= (QLC_83XX_100_CAPABLE |
+                                    QLC_83XX_1G_CAPABLE |
+                                    QLC_83XX_10G_CAPABLE);
+       } else { /* force speed */
+               ahw->port_config &= ~QLC_83XX_AUTONEG_ENABLE;
+               switch (ethtool_cmd_speed(ecmd)) {
+               case SPEED_10:
+                       ahw->port_config &= ~(QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_10_CAPABLE;
+                       break;
+               case SPEED_100:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_100_CAPABLE;
+                       break;
+               case SPEED_1000:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_10G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_1G_CAPABLE;
+                       break;
+               case SPEED_10000:
+                       ahw->port_config &= ~(QLC_83XX_10_CAPABLE |
+                                             QLC_83XX_100_CAPABLE |
+                                             QLC_83XX_1G_CAPABLE);
+                       ahw->port_config |= QLC_83XX_10G_CAPABLE;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
        status = qlcnic_83xx_set_port_config(adapter);
        if (status) {
-               dev_info(&adapter->pdev->dev,
-                        "Failed to Set Link Speed and autoneg.\n");
-               adapter->ahw->port_config = config;
+               netdev_info(adapter->netdev,
+                           "Failed to Set Link Speed and autoneg.\n");
+               ahw->port_config = config;
        }
+
        return status;
 }
 
index 2bf101a..abda0ce 100644 (file)
@@ -360,7 +360,6 @@ enum qlcnic_83xx_states {
 #define QLC_83XX_SFP_MODULE_TYPE(data)         (((data) >> 4) & 0x1F)
 #define QLC_83XX_SFP_CU_LENGTH(data)           (LSB((data) >> 16))
 #define QLC_83XX_SFP_TX_FAULT(data)            ((data) & BIT_10)
-#define QLC_83XX_SFP_10G_CAPABLE(data)         ((data) & BIT_11)
 #define QLC_83XX_LINK_STATS(data)              ((data) & BIT_0)
 #define QLC_83XX_CURRENT_LINK_SPEED(data)      (((data) >> 3) & 7)
 #define QLC_83XX_LINK_PAUSE(data)              (((data) >> 6) & 3)