net/qede/base: add LLDP support
[dpdk.git] / drivers / net / qede / base / ecore_mcp.c
index 5aa3210..f370fb6 100644 (file)
@@ -21,6 +21,7 @@
 #include "ecore_iro.h"
 #include "ecore_dcbx.h"
 #include "ecore_sp_commands.h"
+#include "ecore_cxt.h"
 
 #define CHIP_MCP_RESP_ITER_US 10
 #define EMUL_MCP_RESP_ITER_US (1000 * 1000)
@@ -700,7 +701,7 @@ static void ecore_mcp_mf_workaround(struct ecore_hwfn *p_hwfn,
                load_phase = FW_MSG_CODE_DRV_LOAD_FUNCTION;
 
        /* On CMT, always tell that it's engine */
-       if (p_hwfn->p_dev->num_hwfns > 1)
+       if (ECORE_IS_CMT(p_hwfn->p_dev))
                load_phase = FW_MSG_CODE_DRV_LOAD_ENGINE;
 
        *p_load_code = load_phase;
@@ -1067,8 +1068,6 @@ enum _ecore_status_t ecore_mcp_load_done(struct ecore_hwfn *p_hwfn,
                return rc;
        }
 
-#define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR     (1 << 0)
-
        /* Check if there is a DID mismatch between nvm-cfg/efuse */
        if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR)
                DP_NOTICE(p_hwfn, false,
@@ -1221,6 +1220,28 @@ static void ecore_mcp_read_eee_config(struct ecore_hwfn *p_hwfn,
                p_link->eee_lp_adv_caps |= ECORE_EEE_10G_ADV;
 }
 
+static u32 ecore_mcp_get_shmem_func(struct ecore_hwfn *p_hwfn,
+                                   struct ecore_ptt *p_ptt,
+                                   struct public_func *p_data,
+                                   int pfid)
+{
+       u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base,
+                                       PUBLIC_FUNC);
+       u32 mfw_path_offsize = ecore_rd(p_hwfn, p_ptt, addr);
+       u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid);
+       u32 i, size;
+
+       OSAL_MEM_ZERO(p_data, sizeof(*p_data));
+
+       size = OSAL_MIN_T(u32, sizeof(*p_data),
+                         SECTION_SIZE(mfw_path_offsize));
+       for (i = 0; i < size / sizeof(u32); i++)
+               ((u32 *)p_data)[i] = ecore_rd(p_hwfn, p_ptt,
+                                             func_addr + (i << 2));
+
+       return size;
+}
+
 static void ecore_mcp_handle_link_change(struct ecore_hwfn *p_hwfn,
                                         struct ecore_ptt *p_ptt,
                                         bool b_reset)
@@ -1250,10 +1271,24 @@ static void ecore_mcp_handle_link_change(struct ecore_hwfn *p_hwfn,
                goto out;
        }
 
-       if (p_hwfn->b_drv_link_init)
-               p_link->link_up = !!(status & LINK_STATUS_LINK_UP);
-       else
+       if (p_hwfn->b_drv_link_init) {
+               /* Link indication with modern MFW arrives as per-PF
+                * indication.
+                */
+               if (p_hwfn->mcp_info->capabilities &
+                   FW_MB_PARAM_FEATURE_SUPPORT_VLINK) {
+                       struct public_func shmem_info;
+
+                       ecore_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info,
+                                                MCP_PF_ID(p_hwfn));
+                       p_link->link_up = !!(shmem_info.status &
+                                            FUNC_STATUS_VIRTUAL_LINK_UP);
+               } else {
+                       p_link->link_up = !!(status & LINK_STATUS_LINK_UP);
+               }
+       } else {
                p_link->link_up = false;
+       }
 
        p_link->full_duplex = true;
        switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) {
@@ -1441,7 +1476,7 @@ enum _ecore_status_t ecore_mcp_set_link(struct ecore_hwfn *p_hwfn,
         */
        ecore_mcp_handle_link_change(p_hwfn, p_ptt, !b_up);
 
-       return rc;
+       return ECORE_SUCCESS;
 }
 
 u32 ecore_get_process_kill_counter(struct ecore_hwfn *p_hwfn,
@@ -1516,7 +1551,8 @@ static void ecore_mcp_send_protocol_stats(struct ecore_hwfn *p_hwfn,
                hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN;
                break;
        default:
-               DP_INFO(p_hwfn, "Invalid protocol type %d\n", type);
+               DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
+                          "Invalid protocol type %d\n", type);
                return;
        }
 
@@ -1566,28 +1602,6 @@ static void ecore_read_pf_bandwidth(struct ecore_hwfn *p_hwfn,
        }
 }
 
-static u32 ecore_mcp_get_shmem_func(struct ecore_hwfn *p_hwfn,
-                                   struct ecore_ptt *p_ptt,
-                                   struct public_func *p_data,
-                                   int pfid)
-{
-       u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base,
-                                       PUBLIC_FUNC);
-       u32 mfw_path_offsize = ecore_rd(p_hwfn, p_ptt, addr);
-       u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid);
-       u32 i, size;
-
-       OSAL_MEM_ZERO(p_data, sizeof(*p_data));
-
-       size = OSAL_MIN_T(u32, sizeof(*p_data),
-                         SECTION_SIZE(mfw_path_offsize));
-       for (i = 0; i < size / sizeof(u32); i++)
-               ((u32 *)p_data)[i] = ecore_rd(p_hwfn, p_ptt,
-                                             func_addr + (i << 2));
-
-       return size;
-}
-
 static void
 ecore_mcp_update_bw(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt)
 {
@@ -1860,6 +1874,74 @@ static void ecore_mcp_handle_critical_error(struct ecore_hwfn *p_hwfn,
        ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_HW_ATTN);
 }
 
+void
+ecore_mcp_read_ufp_config(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt)
+{
+       struct public_func shmem_info;
+       u32 port_cfg, val;
+
+       if (!OSAL_TEST_BIT(ECORE_MF_UFP_SPECIFIC, &p_hwfn->p_dev->mf_bits))
+               return;
+
+       OSAL_MEMSET(&p_hwfn->ufp_info, 0, sizeof(p_hwfn->ufp_info));
+       port_cfg = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr +
+                           OFFSETOF(struct public_port, oem_cfg_port));
+       val = GET_MFW_FIELD(port_cfg, OEM_CFG_CHANNEL_TYPE);
+       if (val != OEM_CFG_CHANNEL_TYPE_STAGGED)
+               DP_NOTICE(p_hwfn, false, "Incorrect UFP Channel type  %d\n",
+                         val);
+
+       val = GET_MFW_FIELD(port_cfg, OEM_CFG_SCHED_TYPE);
+       if (val == OEM_CFG_SCHED_TYPE_ETS)
+               p_hwfn->ufp_info.mode = ECORE_UFP_MODE_ETS;
+       else if (val == OEM_CFG_SCHED_TYPE_VNIC_BW)
+               p_hwfn->ufp_info.mode = ECORE_UFP_MODE_VNIC_BW;
+       else
+               DP_NOTICE(p_hwfn, false, "Unknown UFP scheduling mode %d\n",
+                         val);
+
+       ecore_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info,
+                                MCP_PF_ID(p_hwfn));
+       val = GET_MFW_FIELD(shmem_info.oem_cfg_func, OEM_CFG_FUNC_TC);
+       p_hwfn->ufp_info.tc = (u8)val;
+       val = GET_MFW_FIELD(shmem_info.oem_cfg_func,
+                           OEM_CFG_FUNC_HOST_PRI_CTRL);
+       if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_VNIC)
+               p_hwfn->ufp_info.pri_type = ECORE_UFP_PRI_VNIC;
+       else if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_OS)
+               p_hwfn->ufp_info.pri_type = ECORE_UFP_PRI_OS;
+       else
+               DP_NOTICE(p_hwfn, false, "Unknown Host priority control %d\n",
+                         val);
+
+       DP_VERBOSE(p_hwfn, ECORE_MSG_DCB,
+                  "UFP shmem config: mode = %d tc = %d pri_type = %d\n",
+                  p_hwfn->ufp_info.mode, p_hwfn->ufp_info.tc,
+                  p_hwfn->ufp_info.pri_type);
+}
+
+static enum _ecore_status_t
+ecore_mcp_handle_ufp_event(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt)
+{
+       ecore_mcp_read_ufp_config(p_hwfn, p_ptt);
+
+       if (p_hwfn->ufp_info.mode == ECORE_UFP_MODE_VNIC_BW) {
+               p_hwfn->qm_info.ooo_tc = p_hwfn->ufp_info.tc;
+               p_hwfn->hw_info.offload_tc = p_hwfn->ufp_info.tc;
+
+               ecore_qm_reconf(p_hwfn, p_ptt);
+       } else {
+               /* Merge UFP TC with the dcbx TC data */
+               ecore_dcbx_mib_update_event(p_hwfn, p_ptt,
+                                           ECORE_DCBX_OPERATIONAL_MIB);
+       }
+
+       /* update storm FW with negotiation results */
+       ecore_sp_pf_update_ufp(p_hwfn);
+
+       return ECORE_SUCCESS;
+}
+
 enum _ecore_status_t ecore_mcp_handle_events(struct ecore_hwfn *p_hwfn,
                                             struct ecore_ptt *p_ptt)
 {
@@ -1902,6 +1984,15 @@ enum _ecore_status_t ecore_mcp_handle_events(struct ecore_hwfn *p_hwfn,
                case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED:
                        ecore_dcbx_mib_update_event(p_hwfn, p_ptt,
                                                    ECORE_DCBX_OPERATIONAL_MIB);
+                       /* clear the user-config cache */
+                       OSAL_MEMSET(&p_hwfn->p_dcbx_info->set, 0,
+                                   sizeof(struct ecore_dcbx_set));
+                       break;
+               case MFW_DRV_MSG_LLDP_RECEIVED_TLVS_UPDATED:
+                       ecore_lldp_mib_update_event(p_hwfn, p_ptt);
+                       break;
+               case MFW_DRV_MSG_OEM_CFG_UPDATE:
+                       ecore_mcp_handle_ufp_event(p_hwfn, p_ptt);
                        break;
                case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE:
                        ecore_mcp_handle_transceiver_change(p_hwfn, p_ptt);
@@ -3597,8 +3688,108 @@ 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 |
-                  DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE;
+                  DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE |
+                  DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK;
 
        return ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT,
                             features, &mcp_resp, &mcp_param);
 }
+
+enum _ecore_status_t
+ecore_mcp_drv_attribute(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+                       struct ecore_mcp_drv_attr *p_drv_attr)
+{
+       struct attribute_cmd_write_stc attr_cmd_write;
+       enum _attribute_commands_e mfw_attr_cmd;
+       struct ecore_mcp_mb_params mb_params;
+       enum _ecore_status_t rc;
+
+       switch (p_drv_attr->attr_cmd) {
+       case ECORE_MCP_DRV_ATTR_CMD_READ:
+               mfw_attr_cmd = ATTRIBUTE_CMD_READ;
+               break;
+       case ECORE_MCP_DRV_ATTR_CMD_WRITE:
+               mfw_attr_cmd = ATTRIBUTE_CMD_WRITE;
+               break;
+       case ECORE_MCP_DRV_ATTR_CMD_READ_CLEAR:
+               mfw_attr_cmd = ATTRIBUTE_CMD_READ_CLEAR;
+               break;
+       case ECORE_MCP_DRV_ATTR_CMD_CLEAR:
+               mfw_attr_cmd = ATTRIBUTE_CMD_CLEAR;
+               break;
+       default:
+               DP_NOTICE(p_hwfn, false, "Unknown attribute command %d\n",
+                         p_drv_attr->attr_cmd);
+               return ECORE_INVAL;
+       }
+
+       OSAL_MEM_ZERO(&mb_params, sizeof(mb_params));
+       mb_params.cmd = DRV_MSG_CODE_ATTRIBUTE;
+       SET_MFW_FIELD(mb_params.param, DRV_MB_PARAM_ATTRIBUTE_KEY,
+                     p_drv_attr->attr_num);
+       SET_MFW_FIELD(mb_params.param, DRV_MB_PARAM_ATTRIBUTE_CMD,
+                     mfw_attr_cmd);
+       if (p_drv_attr->attr_cmd == ECORE_MCP_DRV_ATTR_CMD_WRITE) {
+               OSAL_MEM_ZERO(&attr_cmd_write, sizeof(attr_cmd_write));
+               attr_cmd_write.val = p_drv_attr->val;
+               attr_cmd_write.mask = p_drv_attr->mask;
+               attr_cmd_write.offset = p_drv_attr->offset;
+
+               mb_params.p_data_src = &attr_cmd_write;
+               mb_params.data_src_size = sizeof(attr_cmd_write);
+       }
+
+       rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+       if (rc != ECORE_SUCCESS)
+               return rc;
+
+       if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) {
+               DP_INFO(p_hwfn,
+                       "The attribute command is not supported by the MFW\n");
+               return ECORE_NOTIMPL;
+       } else if (mb_params.mcp_resp != FW_MSG_CODE_OK) {
+               DP_INFO(p_hwfn,
+                       "Failed to send an attribute command [mcp_resp 0x%x, attr_cmd %d, attr_num %d]\n",
+                       mb_params.mcp_resp, p_drv_attr->attr_cmd,
+                       p_drv_attr->attr_num);
+               return ECORE_INVAL;
+       }
+
+       DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
+                  "Attribute Command: cmd %d [mfw_cmd %d], num %d, in={val 0x%08x, mask 0x%08x, offset 0x%08x}, out={val 0x%08x}\n",
+                  p_drv_attr->attr_cmd, mfw_attr_cmd, p_drv_attr->attr_num,
+                  p_drv_attr->val, p_drv_attr->mask, p_drv_attr->offset,
+                  mb_params.mcp_param);
+
+       if (p_drv_attr->attr_cmd == ECORE_MCP_DRV_ATTR_CMD_READ ||
+           p_drv_attr->attr_cmd == ECORE_MCP_DRV_ATTR_CMD_READ_CLEAR)
+               p_drv_attr->val = mb_params.mcp_param;
+
+       return ECORE_SUCCESS;
+}
+
+void ecore_mcp_wol_wr(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+                     u32 offset, u32 val)
+{
+       struct ecore_mcp_mb_params mb_params = {0};
+       enum _ecore_status_t       rc = ECORE_SUCCESS;
+       u32                        dword = val;
+
+       mb_params.cmd = DRV_MSG_CODE_WRITE_WOL_REG;
+       mb_params.param = offset;
+       mb_params.p_data_src = &dword;
+       mb_params.data_src_size = sizeof(dword);
+
+       rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+       if (rc != ECORE_SUCCESS) {
+               DP_NOTICE(p_hwfn, false,
+                         "Failed to wol write request, rc = %d\n", rc);
+       }
+
+       if (mb_params.mcp_resp != FW_MSG_CODE_WOL_READ_WRITE_OK) {
+               DP_NOTICE(p_hwfn, false,
+                         "Failed to write value 0x%x to offset 0x%x [mcp_resp 0x%x]\n",
+                         val, offset, mb_params.mcp_resp);
+               rc = ECORE_UNKNOWN_ERROR;
+       }
+}