History

qed: prevent a fw assert during device shutdown

Device firmware can assert if the device shutdown path in driver encounters an async. events from mfw (processed in qed_mcp_handle_events()) after qed_mcp_unload_req() returns. A call to qed_mcp_unload_req() currently marks the device as inactive and thus stops any new events, but there is a windows where in-flight events might still be received by the driver. To prevent this race condition, atomically set QED_MCP_BYPASS_PROC_BIT in qed_mcp_unload_req() to make sure qed_mcp_handle_events() ignores all events. Wait for any event that might already be in-process to complete by monitoring QED_MCP_IN_PROCESSING_BIT.

Venkata Sudheer Kumar Bhavaraju committed 4 years ago

Commit ca2d5f11 parent 57ea56b3 files · +51 −2Browse files

Unified · Split

3 files
  1. drivers/net/ethernet/qlogic/qed/qed_dev.c +3 −0
  2. drivers/net/ethernet/qlogic/qed/qed_mcp.c +40 −2
  3. drivers/net/ethernet/qlogic/qed/qed_mcp.h +8 −0
drivers/net/ethernet/qlogic/qed/qed_dev.c+3−0
@@ -3098,6 +3098,9 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params) · 3097 unmodified lines
3098 continue;3098 continue;
3099 }3099 }
3100 3100
3101 /* Some flows may keep variable set */
3102 p_hwfn->mcp_info->mcp_handling_status = 0;
3103
3101 rc = qed_calc_hw_mode(p_hwfn);3104 rc = qed_calc_hw_mode(p_hwfn);
3102 if (rc)3105 if (rc)
3103 return rc;3106 return rc;
drivers/net/ethernet/qlogic/qed/qed_mcp.c+40−2
@@ -140,7 +140,7 @@ static struct qed_mcp_cmd_elem *qed_mcp_cmd_get_elem(struct qed_hwfn *p_hwfn, · 139 unmodified lines
140int qed_mcp_free(struct qed_hwfn *p_hwfn)140int qed_mcp_free(struct qed_hwfn *p_hwfn)
141{141{
142 if (p_hwfn->mcp_info) {142 if (p_hwfn->mcp_info) {
143 struct qed_mcp_cmd_elem *p_cmd_elem, *p_tmp;143 struct qed_mcp_cmd_elem *p_cmd_elem = NULL, *p_tmp;
144 144
145 kfree(p_hwfn->mcp_info->mfw_mb_cur);145 kfree(p_hwfn->mcp_info->mfw_mb_cur);
146 kfree(p_hwfn->mcp_info->mfw_mb_shadow);146 kfree(p_hwfn->mcp_info->mfw_mb_shadow);
@@ -249,6 +249,7 @@ int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) · 102 unmodified lines
249 /* Initialize the MFW spinlock */249 /* Initialize the MFW spinlock */
250 spin_lock_init(&p_info->cmd_lock);250 spin_lock_init(&p_info->cmd_lock);
251 spin_lock_init(&p_info->link_lock);251 spin_lock_init(&p_info->link_lock);
252 spin_lock_init(&p_info->unload_lock);
252 253
253 INIT_LIST_HEAD(&p_info->cmd_list);254 INIT_LIST_HEAD(&p_info->cmd_list);
254 255
@@ -1095,10 +1096,15 @@ int qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) · 840 unmodified lines
1095 return 0;1096 return 0;
1096}1097}
1097 1098
1099#define MFW_COMPLETION_MAX_ITER 5000
1100#define MFW_COMPLETION_INTERVAL_MS 1
1101
1098int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)1102int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
1099{1103{
1100 struct qed_mcp_mb_params mb_params;1104 struct qed_mcp_mb_params mb_params;
1105 u32 cnt = MFW_COMPLETION_MAX_ITER;
1101 u32 wol_param;1106 u32 wol_param;
1107 int rc;
1102 1108
1103 switch (p_hwfn->cdev->wol_config) {1109 switch (p_hwfn->cdev->wol_config) {
1104 case QED_OV_WOL_DISABLED:1110 case QED_OV_WOL_DISABLED:
@@ -1121,7 +1127,23 @@ int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) · 16 unmodified lines
1121 mb_params.param = wol_param;1127 mb_params.param = wol_param;
1122 mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK;1128 mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK;
1123 1129
1124 return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);1130 spin_lock_bh(&p_hwfn->mcp_info->unload_lock);
1131 set_bit(QED_MCP_BYPASS_PROC_BIT,
1132 &p_hwfn->mcp_info->mcp_handling_status);
1133 spin_unlock_bh(&p_hwfn->mcp_info->unload_lock);
1134
1135 rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
1136
1137 while (test_bit(QED_MCP_IN_PROCESSING_BIT,
1138 &p_hwfn->mcp_info->mcp_handling_status) && --cnt)
1139 msleep(MFW_COMPLETION_INTERVAL_MS);
1140
1141 if (!cnt)
1142 DP_NOTICE(p_hwfn,
1143 "Failed to wait MFW event completion after %d msec\n",
1144 MFW_COMPLETION_MAX_ITER * MFW_COMPLETION_INTERVAL_MS);
1145
1146 return rc;
1125}1147}
1126 1148
1127int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)1149int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
@@ -2021,6 +2043,19 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, · 893 unmodified lines
2021 "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n",2043 "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n",
2022 i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]);2044 i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]);
2023 2045
2046 spin_lock_bh(&p_hwfn->mcp_info->unload_lock);
2047 if (test_bit(QED_MCP_BYPASS_PROC_BIT,
2048 &p_hwfn->mcp_info->mcp_handling_status)) {
2049 spin_unlock_bh(&p_hwfn->mcp_info->unload_lock);
2050 DP_INFO(p_hwfn,
2051 "Msg [%d] is bypassed on unload flow\n", i);
2052 continue;
2053 }
2054
2055 set_bit(QED_MCP_IN_PROCESSING_BIT,
2056 &p_hwfn->mcp_info->mcp_handling_status);
2057 spin_unlock_bh(&p_hwfn->mcp_info->unload_lock);
2058
2024 switch (i) {2059 switch (i) {
2025 case MFW_DRV_MSG_LINK_CHANGE:2060 case MFW_DRV_MSG_LINK_CHANGE:
2026 qed_mcp_handle_link_change(p_hwfn, p_ptt, false);2061 qed_mcp_handle_link_change(p_hwfn, p_ptt, false);
@@ -2074,6 +2109,9 @@ int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, · 47 unmodified lines
2074 DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i);2109 DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i);
2075 rc = -EINVAL;2110 rc = -EINVAL;
2076 }2111 }
2112
2113 clear_bit(QED_MCP_IN_PROCESSING_BIT,
2114 &p_hwfn->mcp_info->mcp_handling_status);
2077 }2115 }
2078 2116
2079 /* ACK everything */2117 /* ACK everything */
drivers/net/ethernet/qlogic/qed/qed_mcp.h+8−0
@@ -788,6 +788,14 @@ struct qed_mcp_info { · 787 unmodified lines
788 788
789 /* S/N for debug data mailbox commands */789 /* S/N for debug data mailbox commands */
790 atomic_t dbg_data_seq;790 atomic_t dbg_data_seq;
791
792 /* Spinlock used to sync the flag mcp_handling_status with
793 * the mfw events handler
794 */
795 spinlock_t unload_lock;
796 unsigned long mcp_handling_status;
797#define QED_MCP_BYPASS_PROC_BIT 0
798#define QED_MCP_IN_PROCESSING_BIT 1
791};799};
792 800
793struct qed_mcp_mb_params {801struct qed_mcp_mb_params {