diff options
Diffstat (limited to 'drivers/net/ethernet/intel/i40e/i40e_main.c')
-rw-r--r-- | drivers/net/ethernet/intel/i40e/i40e_main.c | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9dc5829a4e9..4d3a20146cd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -6911,6 +6911,7 @@ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig) **/ static int i40e_setup_pf_switch(struct i40e_pf *pf) { + u32 rxfc, txfc, rxfc_reg; int ret; /* find out what's out there already */ @@ -6981,20 +6982,65 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf) i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); i40e_link_event(pf); - /* Initialize user-specifics link properties */ + /* Initialize user-specific link properties */ pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info & I40E_AQ_AN_COMPLETED) ? true : false); - pf->hw.fc.requested_mode = I40E_FC_DEFAULT; - if (pf->hw.phy.link_info.an_info & - (I40E_AQ_LINK_PAUSE_TX | I40E_AQ_LINK_PAUSE_RX)) + /* requested_mode is set in probe or by ethtool */ + if (!pf->fc_autoneg_status) + goto no_autoneg; + + if ((pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) && + (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)) pf->hw.fc.current_mode = I40E_FC_FULL; else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX) pf->hw.fc.current_mode = I40E_FC_TX_PAUSE; else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX) pf->hw.fc.current_mode = I40E_FC_RX_PAUSE; else - pf->hw.fc.current_mode = I40E_FC_DEFAULT; + pf->hw.fc.current_mode = I40E_FC_NONE; + + /* sync the flow control settings with the auto-neg values */ + switch (pf->hw.fc.current_mode) { + case I40E_FC_FULL: + txfc = 1; + rxfc = 1; + break; + case I40E_FC_TX_PAUSE: + txfc = 1; + rxfc = 0; + break; + case I40E_FC_RX_PAUSE: + txfc = 0; + rxfc = 1; + break; + case I40E_FC_NONE: + case I40E_FC_DEFAULT: + txfc = 0; + rxfc = 0; + break; + case I40E_FC_PFC: + /* TBD */ + break; + /* no default case, we have to handle all possibilities here */ + } + + wr32(&pf->hw, I40E_PRTDCB_FCCFG, txfc << I40E_PRTDCB_FCCFG_TFCE_SHIFT); + + rxfc_reg = rd32(&pf->hw, I40E_PRTDCB_MFLCN) & + ~I40E_PRTDCB_MFLCN_RFCE_MASK; + rxfc_reg |= (rxfc << I40E_PRTDCB_MFLCN_RFCE_SHIFT); + + wr32(&pf->hw, I40E_PRTDCB_MFLCN, rxfc_reg); + goto fc_complete; + +no_autoneg: + /* disable L2 flow control, user can turn it on if they wish */ + wr32(&pf->hw, I40E_PRTDCB_FCCFG, 0); + wr32(&pf->hw, I40E_PRTDCB_MFLCN, rd32(&pf->hw, I40E_PRTDCB_MFLCN) & + ~I40E_PRTDCB_MFLCN_RFCE_MASK); + +fc_complete: return ret; } @@ -7288,6 +7334,9 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pf_reset; } + /* set up a default setting for link flow control */ + pf->hw.fc.requested_mode = I40E_FC_NONE; + err = i40e_init_adminq(hw); dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw)); if (((hw->nvm.version & I40E_NVM_VERSION_HI_MASK) |