Skip to content

Commit

Permalink
qed: Revise load sequence to avoid PCI errors
Browse files Browse the repository at this point in the history
Initiating final cleanup after an ungraceful driver unload can lead to bad
PCI accesses towards the host.
This patch revises the load sequence so final cleanup is sent while the
internal master enable is cleared, to prevent the host accesses, and clears
the internal error indications just before enabling the internal master
enable.

Signed-off-by: Tomer Tayar <tomer.tayar@cavium.com>
Signed-off-by: Ariel Elior <ariel.elior@cavium.com>
Signed-off-by: Michal Kalderon <michal.kalderon@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Tomer Tayar authored and David S. Miller committed Jan 23, 2019
1 parent 1518039 commit cfdb1b6
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 112 deletions.
1 change: 0 additions & 1 deletion drivers/net/ethernet/qlogic/qed/qed.h
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,6 @@ struct qed_hwfn {
u8 dp_level;
char name[NAME_SIZE];

bool first_on_engine;
bool hw_init_done;

u8 num_funcs_on_engine;
Expand Down
117 changes: 68 additions & 49 deletions drivers/net/ethernet/qlogic/qed/qed_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1959,11 +1959,6 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
(p_hwfn->hw_info.personality == QED_PCI_FCOE) ? 1 : 0);
STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0);

/* Cleanup chip from previous driver if such remains exist */
rc = qed_final_cleanup(p_hwfn, p_ptt, rel_pf_id, false);
if (rc)
return rc;

/* Sanity check before the PF init sequence that uses DMAE */
rc = qed_dmae_sanity(p_hwfn, p_ptt, "pf_phase");
if (rc)
Expand Down Expand Up @@ -2007,17 +2002,15 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
return rc;
}

static int qed_change_pci_hwfn(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u8 enable)
int qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, bool b_enable)
{
u32 delay_idx = 0, val, set_val = enable ? 1 : 0;
u32 delay_idx = 0, val, set_val = b_enable ? 1 : 0;

/* Change PF in PXP */
qed_wr(p_hwfn, p_ptt,
PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val);
/* Configure the PF's internal FID_enable for master transactions */
qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, set_val);

/* wait until value is set - try for 1 second every 50us */
/* Wait until value is set - try for 1 second every 50us */
for (delay_idx = 0; delay_idx < 20000; delay_idx++) {
val = qed_rd(p_hwfn, p_ptt,
PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER);
Expand Down Expand Up @@ -2071,13 +2064,19 @@ static int qed_vf_start(struct qed_hwfn *p_hwfn,
return 0;
}

static void qed_pglueb_clear_err(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
{
qed_wr(p_hwfn, p_ptt, PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR,
BIT(p_hwfn->abs_pf_id));
}

int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
{
struct qed_load_req_params load_req_params;
u32 load_code, resp, param, drv_mb_param;
bool b_default_mtu = true;
struct qed_hwfn *p_hwfn;
int rc = 0, mfw_rc, i;
int rc = 0, i;
u16 ether_type;

if ((p_params->int_mode == QED_INT_MODE_MSI) && (cdev->num_hwfns > 1)) {
Expand All @@ -2092,7 +2091,7 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
}

for_each_hwfn(cdev, i) {
struct qed_hwfn *p_hwfn = &cdev->hwfns[i];
p_hwfn = &cdev->hwfns[i];

/* If management didn't provide a default, set one of our own */
if (!p_hwfn->hw_info.mtu) {
Expand All @@ -2105,9 +2104,6 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
continue;
}

/* Enable DMAE in PXP */
rc = qed_change_pci_hwfn(p_hwfn, p_hwfn->p_main_ptt, true);

rc = qed_calc_hw_mode(p_hwfn);
if (rc)
return rc;
Expand Down Expand Up @@ -2148,8 +2144,34 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)

qed_reset_mb_shadow(p_hwfn, p_hwfn->p_main_ptt);

p_hwfn->first_on_engine = (load_code ==
FW_MSG_CODE_DRV_LOAD_ENGINE);
/* Clean up chip from previous driver if such remains exist.
* This is not needed when the PF is the first one on the
* engine, since afterwards we are going to init the FW.
*/
if (load_code != FW_MSG_CODE_DRV_LOAD_ENGINE) {
rc = qed_final_cleanup(p_hwfn, p_hwfn->p_main_ptt,
p_hwfn->rel_pf_id, false);
if (rc) {
DP_NOTICE(p_hwfn, "Final cleanup failed\n");
goto load_err;
}
}

/* Log and clear previous pglue_b errors if such exist */
qed_pglueb_rbc_attn_handler(p_hwfn, p_hwfn->p_main_ptt);

/* Enable the PF's internal FID_enable in the PXP */
rc = qed_pglueb_set_pfid_enable(p_hwfn, p_hwfn->p_main_ptt,
true);
if (rc)
goto load_err;

/* Clear the pglue_b was_error indication.
* In E4 it must be done after the BME and the internal
* FID_enable for the PF are set, since VDMs may cause the
* indication to be set again.
*/
qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt);

switch (load_code) {
case FW_MSG_CODE_DRV_LOAD_ENGINE:
Expand Down Expand Up @@ -2180,39 +2202,29 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
break;
}

if (rc)
if (rc) {
DP_NOTICE(p_hwfn,
"init phase failed for loadcode 0x%x (rc %d)\n",
load_code, rc);
load_code, rc);
goto load_err;
}

/* ACK mfw regardless of success or failure of initialization */
mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
DRV_MSG_CODE_LOAD_DONE,
0, &load_code, &param);
rc = qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt);
if (rc)
return rc;
if (mfw_rc) {
DP_NOTICE(p_hwfn, "Failed sending LOAD_DONE command\n");
return mfw_rc;
}

/* 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,
"warning: device configuration is not supported on this board type. The device may not function as expected.\n");

/* send DCBX attention request command */
DP_VERBOSE(p_hwfn,
QED_MSG_DCB,
"sending phony dcbx set command to trigger DCBx attention handling\n");
mfw_rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
DRV_MSG_CODE_SET_DCBX,
1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT,
&load_code, &param);
if (mfw_rc) {
rc = qed_mcp_cmd(p_hwfn, p_hwfn->p_main_ptt,
DRV_MSG_CODE_SET_DCBX,
1 << DRV_MB_PARAM_DCBX_NOTIFY_SHIFT,
&resp, &param);
if (rc) {
DP_NOTICE(p_hwfn,
"Failed to send DCBX attention request\n");
return mfw_rc;
return rc;
}

p_hwfn->hw_init_done = true;
Expand Down Expand Up @@ -2261,6 +2273,12 @@ int qed_hw_init(struct qed_dev *cdev, struct qed_hw_init_params *p_params)
}

return 0;

load_err:
/* The MFW load lock should be released also when initialization fails.
*/
qed_mcp_load_done(p_hwfn, p_hwfn->p_main_ptt);
return rc;
}

#define QED_HW_STOP_RETRY_LIMIT (10)
Expand Down Expand Up @@ -2395,14 +2413,16 @@ int qed_hw_stop(struct qed_dev *cdev)
p_hwfn = QED_LEADING_HWFN(cdev);
p_ptt = QED_LEADING_HWFN(cdev)->p_main_ptt;

/* Disable DMAE in PXP - in CMT, this should only be done for
* first hw-function, and only after all transactions have
* stopped for all active hw-functions.
/* Clear the PF's internal FID_enable in the PXP.
* In CMT this should only be done for first hw-function, and
* only after all transactions have stopped for all active
* hw-functions.
*/
rc = qed_change_pci_hwfn(p_hwfn, p_ptt, false);
rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false);
if (rc) {
DP_NOTICE(p_hwfn,
"qed_change_pci_hwfn failed. rc = %d.\n", rc);
"qed_pglueb_set_pfid_enable() failed. rc = %d.\n",
rc);
rc2 = -EINVAL;
}
}
Expand Down Expand Up @@ -2502,9 +2522,8 @@ static void qed_hw_hwfn_prepare(struct qed_hwfn *p_hwfn)
PGLUE_B_REG_PGL_ADDR_94_F0_BB, 0);
}

/* Clean Previous errors if such exist */
qed_wr(p_hwfn, p_hwfn->p_main_ptt,
PGLUE_B_REG_WAS_ERROR_PF_31_0_CLR, 1 << p_hwfn->abs_pf_id);
/* Clean previous pglue_b errors if such exist */
qed_pglueb_clear_err(p_hwfn, p_hwfn->p_main_ptt);

/* enable internal target-read */
qed_wr(p_hwfn, p_hwfn->p_main_ptt,
Expand Down
12 changes: 12 additions & 0 deletions drivers/net/ethernet/qlogic/qed/qed_dev_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,18 @@ int qed_get_queue_coalesce(struct qed_hwfn *p_hwfn, u16 *coal, void *handle);
int
qed_set_queue_coalesce(u16 rx_coal, u16 tx_coal, void *p_handle);

/**
* @brief qed_pglueb_set_pfid_enable - Enable or disable PCI BUS MASTER
*
* @param p_hwfn
* @param p_ptt
* @param b_enable - true/false
*
* @return int
*/
int qed_pglueb_set_pfid_enable(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, bool b_enable);

/**
* @brief db_recovery_add - add doorbell information to the doorbell
* recovery mechanism.
Expand Down
Loading

0 comments on commit cfdb1b6

Please sign in to comment.