net/qede/base: add EEE support
authorRasesh Mody <rasesh.mody@cavium.com>
Tue, 19 Sep 2017 01:29:55 +0000 (18:29 -0700)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 6 Oct 2017 00:49:49 +0000 (02:49 +0200)
- Base driver EEE (Energy efficient ethernet) support.
 - Provide supported-speed mask to driver though shared memory.
 - Read/use eee-supported capabilities value from the shared memory.
 - Update qed_fill_link() to advertise the EEE capabilities.

Signed-off-by: Rasesh Mody <rasesh.mody@cavium.com>
drivers/net/qede/base/ecore_dev.c
drivers/net/qede/base/ecore_mcp.c
drivers/net/qede/base/ecore_mcp_api.h
drivers/net/qede/base/mcp_public.h
drivers/net/qede/qede_if.h
drivers/net/qede/qede_main.c

index 93c2306..5c37e1c 100644 (file)
@@ -3108,10 +3108,42 @@ ecore_hw_get_nvm_info(struct ecore_hwfn *p_hwfn,
                                    NVM_CFG1_PORT_DRV_FLOW_CONTROL_TX);
        link->loopback_mode = 0;
 
+       if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) {
+               link_temp = ecore_rd(p_hwfn, p_ptt, port_cfg_addr +
+                                    OFFSETOF(struct nvm_cfg1_port, ext_phy));
+               link_temp &= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_MASK;
+               link_temp >>= NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_OFFSET;
+               p_caps->default_eee = ECORE_MCP_EEE_ENABLED;
+               link->eee.enable = true;
+               switch (link_temp) {
+               case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_DISABLED:
+                       p_caps->default_eee = ECORE_MCP_EEE_DISABLED;
+                       link->eee.enable = false;
+                       break;
+               case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_BALANCED:
+                       p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_BALANCED_TIME;
+                       break;
+               case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_AGGRESSIVE:
+                       p_caps->eee_lpi_timer =
+                               EEE_TX_TIMER_USEC_AGGRESSIVE_TIME;
+                       break;
+               case NVM_CFG1_PORT_EEE_POWER_SAVING_MODE_LOW_LATENCY:
+                       p_caps->eee_lpi_timer = EEE_TX_TIMER_USEC_LATENCY_TIME;
+                       break;
+               }
+
+               link->eee.tx_lpi_timer = p_caps->eee_lpi_timer;
+               link->eee.tx_lpi_enable = link->eee.enable;
+               link->eee.adv_caps = ECORE_EEE_1G_ADV | ECORE_EEE_10G_ADV;
+       } else {
+               p_caps->default_eee = ECORE_MCP_EEE_UNSUPPORTED;
+       }
+
        DP_VERBOSE(p_hwfn, ECORE_MSG_LINK,
-                  "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x\n",
+                  "Read default link: Speed 0x%08x, Adv. Speed 0x%08x, AN: 0x%02x, PAUSE AN: 0x%02x\n EEE: %02x [%08x usec]",
                   link->speed.forced_speed, link->speed.advertised_speeds,
-                  link->speed.autoneg, link->pause.autoneg);
+                  link->speed.autoneg, link->pause.autoneg,
+                  p_caps->default_eee, p_caps->eee_lpi_timer);
 
        /* Read Multi-function information from shmem */
        addr = MCP_REG_SCRATCH + nvm_cfg1_offset +
@@ -3317,6 +3349,27 @@ static void ecore_hw_info_port_num(struct ecore_hwfn *p_hwfn,
                ecore_hw_info_port_num_ah_e5(p_hwfn, p_ptt);
 }
 
+static void ecore_mcp_get_eee_caps(struct ecore_hwfn *p_hwfn,
+                                  struct ecore_ptt *p_ptt)
+{
+       struct ecore_mcp_link_capabilities *p_caps;
+       u32 eee_status;
+
+       p_caps = &p_hwfn->mcp_info->link_capabilities;
+       if (p_caps->default_eee == ECORE_MCP_EEE_UNSUPPORTED)
+               return;
+
+       p_caps->eee_speed_caps = 0;
+       eee_status = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
+                             OFFSETOF(struct public_port, eee_status));
+       eee_status = (eee_status & EEE_SUPPORTED_SPEED_MASK) >>
+                       EEE_SUPPORTED_SPEED_OFFSET;
+       if (eee_status & EEE_1G_SUPPORTED)
+               p_caps->eee_speed_caps |= ECORE_EEE_1G_ADV;
+       if (eee_status & EEE_10G_ADV)
+               p_caps->eee_speed_caps |= ECORE_EEE_10G_ADV;
+}
+
 static enum _ecore_status_t
 ecore_get_hw_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
                  enum ecore_pci_personality personality,
@@ -3386,6 +3439,8 @@ ecore_get_hw_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
                            p_hwfn->mcp_info->func_info.ovlan;
 
                ecore_mcp_cmd_port_init(p_hwfn, p_ptt);
+
+               ecore_mcp_get_eee_caps(p_hwfn, p_ptt);
        }
 
        if (personality != ECORE_PCI_DEFAULT) {
index 462fcc9..3be23ba 100644 (file)
@@ -1036,6 +1036,29 @@ static void ecore_mcp_handle_transceiver_change(struct ecore_hwfn *p_hwfn,
                DP_NOTICE(p_hwfn, false, "Transceiver is unplugged.\n");
 }
 
+static void ecore_mcp_read_eee_config(struct ecore_hwfn *p_hwfn,
+                                     struct ecore_ptt *p_ptt,
+                                     struct ecore_mcp_link_state *p_link)
+{
+       u32 eee_status, val;
+
+       p_link->eee_adv_caps = 0;
+       p_link->eee_lp_adv_caps = 0;
+       eee_status = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
+                                    OFFSETOF(struct public_port, eee_status));
+       p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT);
+       val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_SHIFT;
+       if (val & EEE_1G_ADV)
+               p_link->eee_adv_caps |= ECORE_EEE_1G_ADV;
+       if (val & EEE_10G_ADV)
+               p_link->eee_adv_caps |= ECORE_EEE_10G_ADV;
+       val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_SHIFT;
+       if (val & EEE_1G_ADV)
+               p_link->eee_lp_adv_caps |= ECORE_EEE_1G_ADV;
+       if (val & EEE_10G_ADV)
+               p_link->eee_lp_adv_caps |= ECORE_EEE_10G_ADV;
+}
+
 static void ecore_mcp_handle_link_change(struct ecore_hwfn *p_hwfn,
                                         struct ecore_ptt *p_ptt,
                                         bool b_reset)
@@ -1170,6 +1193,9 @@ static void ecore_mcp_handle_link_change(struct ecore_hwfn *p_hwfn,
 
        p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT);
 
+       if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE)
+               ecore_mcp_read_eee_config(p_hwfn, p_ptt, p_link);
+
        OSAL_LINK_UPDATE(p_hwfn);
 }
 
@@ -1197,6 +1223,27 @@ enum _ecore_status_t ecore_mcp_set_link(struct ecore_hwfn *p_hwfn,
        phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0;
        phy_cfg.adv_speed = params->speed.advertised_speeds;
        phy_cfg.loopback_mode = params->loopback_mode;
+
+       /* There are MFWs that share this capability regardless of whether
+        * this is feasible or not. And given that at the very least adv_caps
+        * would be set internally by ecore, we want to make sure LFA would
+        * still work.
+        */
+       if ((p_hwfn->mcp_info->capabilities &
+            FW_MB_PARAM_FEATURE_SUPPORT_EEE) &&
+           params->eee.enable) {
+               phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED;
+               if (params->eee.tx_lpi_enable)
+                       phy_cfg.eee_cfg |= EEE_CFG_TX_LPI;
+               if (params->eee.adv_caps & ECORE_EEE_1G_ADV)
+                       phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G;
+               if (params->eee.adv_caps & ECORE_EEE_10G_ADV)
+                       phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G;
+               phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer <<
+                                   EEE_TX_TIMER_USEC_SHIFT) &
+                                       EEE_TX_TIMER_USEC_MASK;
+       }
+
        p_hwfn->b_drv_link_init = b_up;
 
        if (b_up)
@@ -3331,7 +3378,8 @@ enum _ecore_status_t ecore_mcp_set_capabilities(struct ecore_hwfn *p_hwfn,
 {
        u32 mcp_resp, mcp_param, features;
 
-       features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_SMARTLINQ;
+       features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_SMARTLINQ |
+                  DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE;
 
        return ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT,
                             features, &mcp_resp, &mcp_param);
index 059b55e..a3d6bc1 100644 (file)
@@ -23,16 +23,37 @@ struct ecore_mcp_link_pause_params {
        bool forced_tx;
 };
 
+enum ecore_mcp_eee_mode {
+       ECORE_MCP_EEE_DISABLED,
+       ECORE_MCP_EEE_ENABLED,
+       ECORE_MCP_EEE_UNSUPPORTED
+};
+
+struct ecore_link_eee_params {
+       u32 tx_lpi_timer;
+#define ECORE_EEE_1G_ADV       (1 << 0)
+#define ECORE_EEE_10G_ADV      (1 << 1)
+       /* Capabilities are represented using ECORE_EEE_*_ADV values */
+       u8 adv_caps;
+       u8 lp_adv_caps;
+       bool enable;
+       bool tx_lpi_enable;
+};
+
 struct ecore_mcp_link_params {
        struct ecore_mcp_link_speed_params speed;
        struct ecore_mcp_link_pause_params pause;
        u32 loopback_mode; /* in PMM_LOOPBACK values */
+       struct ecore_link_eee_params eee;
 };
 
 struct ecore_mcp_link_capabilities {
        u32 speed_capabilities;
        bool default_speed_autoneg; /* In Mb/s */
        u32 default_speed; /* In Mb/s */
+       enum ecore_mcp_eee_mode default_eee;
+       u32 eee_lpi_timer;
+       u8 eee_speed_caps;
 };
 
 struct ecore_mcp_link_state {
@@ -67,6 +88,10 @@ struct ecore_mcp_link_state {
        u8 partner_adv_pause;
 
        bool sfp_tx_fault;
+
+       bool eee_active;
+       u8 eee_adv_caps;
+       u8 eee_lp_adv_caps;
 };
 
 struct ecore_mcp_function_info {
index f934c17..af6a45e 100644 (file)
@@ -792,6 +792,12 @@ struct public_port {
 #define        EEE_LP_ADV_STATUS_MASK  0x00000f00
 #define EEE_LP_ADV_STATUS_SHIFT        8
 
+/* Supported speeds for EEE */
+#define EEE_SUPPORTED_SPEED_MASK       0x0000f000
+#define EEE_SUPPORTED_SPEED_OFFSET     12
+       #define EEE_1G_SUPPORTED        (1 << 1)
+       #define EEE_10G_SUPPORTED       (1 << 2)
+
        u32 eee_remote; /* Used for EEE in LLDP */
 #define EEE_REMOTE_TW_TX_MASK  0x0000ffff
 #define EEE_REMOTE_TW_TX_SHIFT 0
index 42560d5..02af2ee 100644 (file)
@@ -83,6 +83,7 @@ struct qed_link_params {
 #define QED_LINK_OVERRIDE_SPEED_ADV_SPEEDS      (1 << 1)
 #define QED_LINK_OVERRIDE_SPEED_FORCED_SPEED    (1 << 2)
 #define QED_LINK_OVERRIDE_PAUSE_CONFIG          (1 << 3)
+#define QED_LINK_OVERRIDE_EEE_CONFIG           (1 << 5)
        uint32_t override_flags;
        bool autoneg;
        uint32_t adv_speeds;
@@ -91,6 +92,7 @@ struct qed_link_params {
 #define QED_LINK_PAUSE_RX_ENABLE                (1 << 1)
 #define QED_LINK_PAUSE_TX_ENABLE                (1 << 2)
        uint32_t pause_config;
+       struct ecore_link_eee_params eee;
 };
 
 struct qed_link_output {
@@ -104,6 +106,12 @@ struct qed_link_output {
        uint8_t port;           /* In PORT defs */
        bool autoneg;
        uint32_t pause_config;
+
+       /* EEE - capability & param */
+       bool eee_supported;
+       bool eee_active;
+       u8 sup_caps;
+       struct ecore_link_eee_params eee;
 };
 
 struct qed_slowpath_params {
index 9be8f80..13b321d 100644 (file)
@@ -539,6 +539,21 @@ static void qed_fill_link(struct ecore_hwfn *hwfn,
 
        if (params.pause.forced_tx)
                if_link->pause_config |= QED_LINK_PAUSE_TX_ENABLE;
+
+       if (link_caps.default_eee == ECORE_MCP_EEE_UNSUPPORTED) {
+               if_link->eee_supported = false;
+       } else {
+               if_link->eee_supported = true;
+               if_link->eee_active = link.eee_active;
+               if_link->sup_caps = link_caps.eee_speed_caps;
+               /* MFW clears adv_caps on eee disable; use configured value */
+               if_link->eee.adv_caps = link.eee_adv_caps ? link.eee_adv_caps :
+                                       params.eee.adv_caps;
+               if_link->eee.lp_adv_caps = link.eee_lp_adv_caps;
+               if_link->eee.enable = params.eee.enable;
+               if_link->eee.tx_lpi_enable = params.eee.tx_lpi_enable;
+               if_link->eee.tx_lpi_timer = params.eee.tx_lpi_timer;
+       }
 }
 
 static void
@@ -588,6 +603,10 @@ static int qed_set_link(struct ecore_dev *edev, struct qed_link_params *params)
                        link_params->pause.forced_tx = false;
        }
 
+       if (params->override_flags & QED_LINK_OVERRIDE_EEE_CONFIG)
+               memcpy(&link_params->eee, &params->eee,
+                      sizeof(link_params->eee));
+
        rc = ecore_mcp_set_link(hwfn, ptt, params->link_up);
 
        ecore_ptt_release(hwfn, ptt);