Commit e40a826a authored by Sudarsana Reddy Kalluru's avatar Sudarsana Reddy Kalluru Committed by David S. Miller

qed: Add support for virtual link.

Currently driver registers to physical link notifications (of the device)
from Management firmware (MFW). Driver doesn't get notified if there's a
change in the virtual link e.g., link-flap on the peer PF interface.
Virtual link indication from MFW reflects the per PF link status instead
of the physical link.

The patch adds driver support for,
  - Advertising the virtual link support to MFW.
  - Handling the virtual link notification from MFW.

Please consider applying it to 'net-next'.
Signed-off-by: default avatarSudarsana Reddy Kalluru <Sudarsana.Kalluru@cavium.com>
Signed-off-by: default avatarTomer Tayar <Tomer.Tayar@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b1871915
...@@ -12276,7 +12276,7 @@ struct public_func { ...@@ -12276,7 +12276,7 @@ struct public_func {
#define FUNC_MF_CFG_MAX_BW_DEFAULT 0x00640000 #define FUNC_MF_CFG_MAX_BW_DEFAULT 0x00640000
u32 status; u32 status;
#define FUNC_STATUS_VLINK_DOWN 0x00000001 #define FUNC_STATUS_VIRTUAL_LINK_UP 0x00000001
u32 mac_upper; u32 mac_upper;
#define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff #define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff
...@@ -12698,6 +12698,7 @@ struct public_drv_mb { ...@@ -12698,6 +12698,7 @@ struct public_drv_mb {
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_MASK 0x0000FFFF #define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_MASK 0x0000FFFF
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_OFFSET 0 #define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_OFFSET 0
#define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE 0x00000002 #define DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE 0x00000002
#define DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK 0x00010000
u32 fw_mb_header; u32 fw_mb_header;
#define FW_MSG_CODE_MASK 0xffff0000 #define FW_MSG_CODE_MASK 0xffff0000
...@@ -12750,6 +12751,7 @@ struct public_drv_mb { ...@@ -12750,6 +12751,7 @@ struct public_drv_mb {
/* get MFW feature support response */ /* get MFW feature support response */
#define FW_MB_PARAM_FEATURE_SUPPORT_EEE 0x00000002 #define FW_MB_PARAM_FEATURE_SUPPORT_EEE 0x00000002
#define FW_MB_PARAM_FEATURE_SUPPORT_VLINK 0x00010000
#define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR (1 << 0) #define FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR (1 << 0)
......
...@@ -1247,6 +1247,52 @@ static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn, ...@@ -1247,6 +1247,52 @@ static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn,
p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV; p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV;
} }
static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn,
struct qed_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 = qed_rd(p_hwfn, p_ptt, addr);
u32 func_addr;
u32 i, size;
func_addr = SECTION_ADDR(mfw_path_offsize, pfid);
memset(p_data, 0, sizeof(*p_data));
size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize));
for (i = 0; i < size / sizeof(u32); i++)
((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt,
func_addr + (i << 2));
return size;
}
static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn,
struct public_func *p_shmem_info)
{
struct qed_mcp_function_info *p_info;
p_info = &p_hwfn->mcp_info->func_info;
p_info->bandwidth_min = QED_MFW_GET_FIELD(p_shmem_info->config,
FUNC_MF_CFG_MIN_BW);
if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) {
DP_INFO(p_hwfn,
"bandwidth minimum out of bounds [%02x]. Set to 1\n",
p_info->bandwidth_min);
p_info->bandwidth_min = 1;
}
p_info->bandwidth_max = QED_MFW_GET_FIELD(p_shmem_info->config,
FUNC_MF_CFG_MAX_BW);
if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) {
DP_INFO(p_hwfn,
"bandwidth maximum out of bounds [%02x]. Set to 100\n",
p_info->bandwidth_max);
p_info->bandwidth_max = 100;
}
}
static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, bool b_reset) struct qed_ptt *p_ptt, bool b_reset)
{ {
...@@ -1274,10 +1320,29 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, ...@@ -1274,10 +1320,29 @@ static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn,
goto out; goto out;
} }
if (p_hwfn->b_drv_link_init) if (p_hwfn->b_drv_link_init) {
p_link->link_up = !!(status & LINK_STATUS_LINK_UP); /* Link indication with modern MFW arrives as per-PF
else * indication.
*/
if (p_hwfn->mcp_info->capabilities &
FW_MB_PARAM_FEATURE_SUPPORT_VLINK) {
struct public_func shmem_info;
qed_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);
qed_read_pf_bandwidth(p_hwfn, &shmem_info);
DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
"Virtual link_up = %d\n", p_link->link_up);
} else {
p_link->link_up = !!(status & LINK_STATUS_LINK_UP);
DP_VERBOSE(p_hwfn, NETIF_MSG_LINK,
"Physical link_up = %d\n", p_link->link_up);
}
} else {
p_link->link_up = false; p_link->link_up = false;
}
p_link->full_duplex = true; p_link->full_duplex = true;
switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) {
...@@ -1504,53 +1569,6 @@ static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, ...@@ -1504,53 +1569,6 @@ static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn,
qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
} }
static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn,
struct public_func *p_shmem_info)
{
struct qed_mcp_function_info *p_info;
p_info = &p_hwfn->mcp_info->func_info;
p_info->bandwidth_min = (p_shmem_info->config &
FUNC_MF_CFG_MIN_BW_MASK) >>
FUNC_MF_CFG_MIN_BW_SHIFT;
if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) {
DP_INFO(p_hwfn,
"bandwidth minimum out of bounds [%02x]. Set to 1\n",
p_info->bandwidth_min);
p_info->bandwidth_min = 1;
}
p_info->bandwidth_max = (p_shmem_info->config &
FUNC_MF_CFG_MAX_BW_MASK) >>
FUNC_MF_CFG_MAX_BW_SHIFT;
if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) {
DP_INFO(p_hwfn,
"bandwidth maximum out of bounds [%02x]. Set to 100\n",
p_info->bandwidth_max);
p_info->bandwidth_max = 100;
}
}
static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn,
struct qed_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 = qed_rd(p_hwfn, p_ptt, addr);
u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid);
u32 i, size;
memset(p_data, 0, sizeof(*p_data));
size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize));
for (i = 0; i < size / sizeof(u32); i++)
((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt,
func_addr + (i << 2));
return size;
}
static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{ {
struct qed_mcp_function_info *p_info; struct qed_mcp_function_info *p_info;
...@@ -3351,7 +3369,8 @@ int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) ...@@ -3351,7 +3369,8 @@ int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{ {
u32 mcp_resp, mcp_param, features; u32 mcp_resp, mcp_param, features;
features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE; features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE |
DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK;
return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT, return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT,
features, &mcp_resp, &mcp_param); features, &mcp_resp, &mcp_param);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment