Commit 1bbf148d authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next

Jeff Kirsher says:

====================
Intel Wired LAN Driver Updates 2014-11-18

This series contains updates to i40e only.

Shannon provides a patch to clean up the driver to only warn once that
PTP is not supported when linked at 100Mbps.

Mitch provides a fix for i40e where the VF interrupt processing takes
a long time and it is possible that we could lose a VFLR event if it
happens while processing a VFLR on another VF.  To correct this situation,
we enable the VFLR interrupt cause before we begin processing any pending
resets.

Neerav provides several patches to update DCB support in i40e.  When
there are DCB configuration changes based on DCBx, the firmware suspends
the port's Tx and generates an event to the PF.  The PF is then
responsible to reconfigure the PF VSIs and switching topology as per the
updated DCB configuration and then resume the port's Tx by calling the
"Resume Port Tx" AQ command, so add this call to the flow that handles
DCB re-configuration in the PF.  Allow the driver to query and use DCB
configuration from firmware when firmware DCBx agent is in CEE mode.
Add a check whether LLDP Agent's default AdminStatus is enabled or
disabled on a given port, and sets DCBx status to disabled if the
status is disabled.  Fix an issue when the port TC configuration
changes as a result of DCBx and the driver modifies the enabled TCs for
the VEBs it manages but does not update the enabled_tc value that
was cached on a per VEB basis.  Add a new PF state so that if a port's
Tx is in suspended state the Tx queue disable flow would just put the
request for the queue to be disabled and return without waiting for the
queue to be actually disabled.  Allows the driver to enable/disable
the XPS based on the number of TCs being enabled for the given VSI.

v2: Dropped patch "i40e: Handle a single mss packet with more than 8 frags"
    while we rework the patch after we test a bit more based on feedback from
    Eric Dumazet.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cadaecd2 3ffa037d
......@@ -146,6 +146,7 @@ enum i40e_state_t {
__I40E_DOWN_REQUESTED,
__I40E_FD_FLUSH_REQUESTED,
__I40E_RESET_FAILED,
__I40E_PORT_TX_SUSPENDED,
};
enum i40e_interrupt_policy {
......
......@@ -255,6 +255,7 @@ enum i40e_admin_queue_opc {
i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
i40e_aqc_opc_lldp_stop = 0x0A05,
i40e_aqc_opc_lldp_start = 0x0A06,
i40e_aqc_opc_get_cee_dcb_cfg = 0x0A07,
/* Tunnel commands */
i40e_aqc_opc_add_udp_tunnel = 0x0B00,
......@@ -1987,10 +1988,50 @@ struct i40e_aqc_lldp_start {
I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start);
/* Apply MIB changes (0x0A07)
* uses the generic struc as it contains no data
/* Get CEE DCBX Oper Config (0x0A07)
* uses the generic descriptor struct
* returns below as indirect response
*/
#define I40E_AQC_CEE_APP_FCOE_SHIFT 0x0
#define I40E_AQC_CEE_APP_FCOE_MASK (0x7 << I40E_AQC_CEE_APP_FCOE_SHIFT)
#define I40E_AQC_CEE_APP_ISCSI_SHIFT 0x3
#define I40E_AQC_CEE_APP_ISCSI_MASK (0x7 << I40E_AQC_CEE_APP_ISCSI_SHIFT)
#define I40E_AQC_CEE_APP_FIP_SHIFT 0x8
#define I40E_AQC_CEE_APP_FIP_MASK (0x7 << I40E_AQC_CEE_APP_FIP_SHIFT)
#define I40E_AQC_CEE_PG_STATUS_SHIFT 0x0
#define I40E_AQC_CEE_PG_STATUS_MASK (0x7 << I40E_AQC_CEE_PG_STATUS_SHIFT)
#define I40E_AQC_CEE_PFC_STATUS_SHIFT 0x3
#define I40E_AQC_CEE_PFC_STATUS_MASK (0x7 << I40E_AQC_CEE_PFC_STATUS_SHIFT)
#define I40E_AQC_CEE_APP_STATUS_SHIFT 0x8
#define I40E_AQC_CEE_APP_STATUS_MASK (0x7 << I40E_AQC_CEE_APP_STATUS_SHIFT)
struct i40e_aqc_get_cee_dcb_cfg_v1_resp {
u8 reserved1;
u8 oper_num_tc;
u8 oper_prio_tc[4];
u8 reserved2;
u8 oper_tc_bw[8];
u8 oper_pfc_en;
u8 reserved3;
__le16 oper_app_prio;
u8 reserved4;
__le16 tlv_status;
};
I40E_CHECK_STRUCT_LEN(0x18, i40e_aqc_get_cee_dcb_cfg_v1_resp);
struct i40e_aqc_get_cee_dcb_cfg_resp {
u8 oper_num_tc;
u8 oper_prio_tc[4];
u8 oper_tc_bw[8];
u8 oper_pfc_en;
__le16 oper_app_prio;
__le32 tlv_status;
u8 reserved[12];
};
I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_cee_dcb_cfg_resp);
/* Add Udp Tunnel command and completion (direct 0x0B00) */
struct i40e_aqc_add_udp_tunnel {
__le16 udp_port;
......
......@@ -2659,6 +2659,34 @@ i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
return status;
}
/**
* i40e_aq_get_cee_dcb_config
* @hw: pointer to the hw struct
* @buff: response buffer that stores CEE operational configuration
* @buff_size: size of the buffer passed
* @cmd_details: pointer to command details structure or NULL
*
* Get CEE DCBX mode operational configuration from firmware
**/
i40e_status i40e_aq_get_cee_dcb_config(struct i40e_hw *hw,
void *buff, u16 buff_size,
struct i40e_asq_cmd_details *cmd_details)
{
struct i40e_aq_desc desc;
i40e_status status;
if (buff_size == 0 || !buff)
return I40E_ERR_PARAM;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_cee_dcb_cfg);
desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
status = i40e_asq_send_command(hw, &desc, (void *)buff, buff_size,
cmd_details);
return status;
}
/**
* i40e_aq_add_udp_tunnel
* @hw: pointer to the hw struct
......@@ -3216,6 +3244,26 @@ i40e_status i40e_aq_add_rem_control_packet_filter(struct i40e_hw *hw,
return status;
}
/**
* i40e_aq_resume_port_tx
* @hw: pointer to the hardware structure
* @cmd_details: pointer to command details structure or NULL
*
* Resume port's Tx traffic
**/
i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details)
{
struct i40e_aq_desc desc;
i40e_status status;
i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_resume_port_tx);
status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
return status;
}
/**
* i40e_set_pci_config_data - store PCI bus info
* @hw: pointer to hardware structure
......
......@@ -59,7 +59,7 @@ i40e_status i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
struct i40e_dcbx_config *dcbcfg)
{
struct i40e_ieee_ets_config *etscfg;
struct i40e_dcb_ets_config *etscfg;
u8 *buf = tlv->tlvinfo;
u16 offset = 0;
u8 priority;
......@@ -406,6 +406,166 @@ i40e_status i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
return ret;
}
/**
* i40e_cee_to_dcb_v1_config
* @cee_cfg: pointer to CEE v1 response configuration struct
* @dcbcfg: DCB configuration struct
*
* Convert CEE v1 configuration from firmware to DCB configuration
**/
static void i40e_cee_to_dcb_v1_config(
struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
struct i40e_dcbx_config *dcbcfg)
{
u16 status, tlv_status = le16_to_cpu(cee_cfg->tlv_status);
u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
u8 i, tc, err, sync, oper;
/* CEE PG data to ETS config */
dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
for (i = 0; i < 4; i++) {
tc = (u8)((cee_cfg->oper_prio_tc[i] &
I40E_CEE_PGID_PRIO_1_MASK) >>
I40E_CEE_PGID_PRIO_1_SHIFT);
dcbcfg->etscfg.prioritytable[i*2] = tc;
tc = (u8)((cee_cfg->oper_prio_tc[i] &
I40E_CEE_PGID_PRIO_0_MASK) >>
I40E_CEE_PGID_PRIO_0_SHIFT);
dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
}
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
/* Map it to next empty TC */
dcbcfg->etscfg.prioritytable[i] =
cee_cfg->oper_num_tc - 1;
dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
} else {
dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
}
}
/* CEE PFC data to ETS config */
dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
I40E_AQC_CEE_APP_STATUS_SHIFT;
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
/* Add APPs if Error is False and Oper/Sync is True */
if (!err && sync && oper) {
/* CEE operating configuration supports FCoE/iSCSI/FIP only */
dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
/* FCoE APP */
dcbcfg->app[0].priority =
(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
I40E_AQC_CEE_APP_FCOE_SHIFT;
dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
/* iSCSI APP */
dcbcfg->app[1].priority =
(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
I40E_AQC_CEE_APP_ISCSI_SHIFT;
dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
/* FIP APP */
dcbcfg->app[2].priority =
(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
I40E_AQC_CEE_APP_FIP_SHIFT;
dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
}
}
/**
* i40e_cee_to_dcb_config
* @cee_cfg: pointer to CEE configuration struct
* @dcbcfg: DCB configuration struct
*
* Convert CEE configuration from firmware to DCB configuration
**/
static void i40e_cee_to_dcb_config(
struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
struct i40e_dcbx_config *dcbcfg)
{
u32 status, tlv_status = le32_to_cpu(cee_cfg->tlv_status);
u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
u8 i, tc, err, sync, oper;
/* CEE PG data to ETS config */
dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
for (i = 0; i < 4; i++) {
tc = (u8)((cee_cfg->oper_prio_tc[i] &
I40E_CEE_PGID_PRIO_1_MASK) >>
I40E_CEE_PGID_PRIO_1_SHIFT);
dcbcfg->etscfg.prioritytable[i*2] = tc;
tc = (u8)((cee_cfg->oper_prio_tc[i] &
I40E_CEE_PGID_PRIO_0_MASK) >>
I40E_CEE_PGID_PRIO_0_SHIFT);
dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
}
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
/* Map it to next empty TC */
dcbcfg->etscfg.prioritytable[i] =
cee_cfg->oper_num_tc - 1;
dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
} else {
dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
}
}
/* CEE PFC data to ETS config */
dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
I40E_AQC_CEE_APP_STATUS_SHIFT;
err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
/* Add APPs if Error is False and Oper/Sync is True */
if (!err && sync && oper) {
/* CEE operating configuration supports FCoE/iSCSI/FIP only */
dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
/* FCoE APP */
dcbcfg->app[0].priority =
(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
I40E_AQC_CEE_APP_FCOE_SHIFT;
dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
/* iSCSI APP */
dcbcfg->app[1].priority =
(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
I40E_AQC_CEE_APP_ISCSI_SHIFT;
dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
/* FIP APP */
dcbcfg->app[2].priority =
(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
I40E_AQC_CEE_APP_FIP_SHIFT;
dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
}
}
/**
* i40e_get_dcb_config
* @hw: pointer to the hw struct
......@@ -415,7 +575,44 @@ i40e_status i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
i40e_status i40e_get_dcb_config(struct i40e_hw *hw)
{
i40e_status ret = 0;
struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
/* If Firmware version < v4.33 IEEE only */
if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
(hw->aq.fw_maj_ver < 4))
goto ieee;
/* If Firmware version == v4.33 use old CEE struct */
if ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33)) {
ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
sizeof(cee_v1_cfg), NULL);
if (!ret) {
/* CEE mode */
hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
&hw->local_dcbx_config);
}
} else {
ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
sizeof(cee_cfg), NULL);
if (!ret) {
/* CEE mode */
hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
i40e_cee_to_dcb_config(&cee_cfg,
&hw->local_dcbx_config);
}
}
/* CEE mode not enabled try querying IEEE data */
if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
goto ieee;
else
goto out;
ieee:
/* IEEE mode */
hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
/* Get Local DCB Config */
ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
&hw->local_dcbx_config);
......@@ -426,6 +623,10 @@ i40e_status i40e_get_dcb_config(struct i40e_hw *hw)
ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
&hw->remote_dcbx_config);
/* Don't treat ENOENT as an error for Remote MIBs */
if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
ret = 0;
out:
return ret;
}
......@@ -439,10 +640,27 @@ i40e_status i40e_get_dcb_config(struct i40e_hw *hw)
i40e_status i40e_init_dcb(struct i40e_hw *hw)
{
i40e_status ret = 0;
struct i40e_lldp_variables lldp_cfg;
u8 adminstatus = 0;
if (!hw->func_caps.dcb)
return ret;
/* Read LLDP NVM area */
ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
if (ret)
return ret;
/* Get the LLDP AdminStatus for the current port */
adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
adminstatus &= 0xF;
/* LLDP agent disabled */
if (!adminstatus) {
hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
return ret;
}
/* Get DCBX status */
ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
if (ret)
......@@ -454,6 +672,8 @@ i40e_status i40e_init_dcb(struct i40e_hw *hw)
case I40E_DCBX_STATUS_IN_PROGRESS:
/* Get current DCBX configuration */
ret = i40e_get_dcb_config(hw);
if (ret)
return ret;
break;
case I40E_DCBX_STATUS_DISABLED:
return ret;
......@@ -470,3 +690,33 @@ i40e_status i40e_init_dcb(struct i40e_hw *hw)
return ret;
}
/**
* i40e_read_lldp_cfg - read LLDP Configuration data from NVM
* @hw: pointer to the HW structure
* @lldp_cfg: pointer to hold lldp configuration variables
*
* Reads the LLDP configuration data from NVM
**/
i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
struct i40e_lldp_variables *lldp_cfg)
{
i40e_status ret = 0;
u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
if (!lldp_cfg)
return I40E_ERR_PARAM;
ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
if (ret)
goto err_lldp_cfg;
ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
sizeof(struct i40e_lldp_variables),
(u8 *)lldp_cfg,
true, NULL);
i40e_release_nvm(hw);
err_lldp_cfg:
return ret;
}
......@@ -65,6 +65,11 @@
#define I40E_IEEE_ETS_PRIO_0_MASK (0x7 << I40E_IEEE_ETS_PRIO_0_SHIFT)
#define I40E_IEEE_ETS_PRIO_1_SHIFT 4
#define I40E_IEEE_ETS_PRIO_1_MASK (0x7 << I40E_IEEE_ETS_PRIO_1_SHIFT)
#define I40E_CEE_PGID_PRIO_0_SHIFT 0
#define I40E_CEE_PGID_PRIO_0_MASK (0xF << I40E_CEE_PGID_PRIO_0_SHIFT)
#define I40E_CEE_PGID_PRIO_1_SHIFT 4
#define I40E_CEE_PGID_PRIO_1_MASK (0xF << I40E_CEE_PGID_PRIO_1_SHIFT)
#define I40E_CEE_PGID_STRICT 15
/* Defines for IEEE TSA types */
#define I40E_IEEE_TSA_STRICT 0
......
......@@ -207,7 +207,7 @@ void i40e_dcbnl_set_all(struct i40e_vsi *vsi)
* VSI
**/
static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi,
struct i40e_ieee_app_priority_table *app)
struct i40e_dcb_app_priority_table *app)
{
struct net_device *dev = vsi->netdev;
struct dcb_app sapp;
......@@ -229,7 +229,7 @@ static int i40e_dcbnl_vsi_del_app(struct i40e_vsi *vsi,
* Delete given APP from all the VSIs for given PF
**/
static void i40e_dcbnl_del_app(struct i40e_pf *pf,
struct i40e_ieee_app_priority_table *app)
struct i40e_dcb_app_priority_table *app)
{
int v, err;
for (v = 0; v < pf->num_alloc_vsi; v++) {
......@@ -252,7 +252,7 @@ static void i40e_dcbnl_del_app(struct i40e_pf *pf,
* Find given APP in the DCB configuration
**/
static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,
struct i40e_ieee_app_priority_table *app)
struct i40e_dcb_app_priority_table *app)
{
int i;
......@@ -277,7 +277,7 @@ static bool i40e_dcbnl_find_app(struct i40e_dcbx_config *cfg,
void i40e_dcbnl_flush_apps(struct i40e_pf *pf,
struct i40e_dcbx_config *new_cfg)
{
struct i40e_ieee_app_priority_table app;
struct i40e_dcb_app_priority_table app;
struct i40e_dcbx_config *dcbxcfg;
struct i40e_hw *hw = &pf->hw;
int i;
......
......@@ -1312,6 +1312,8 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
kfree(bw_data);
bw_data = NULL;
dev_info(&pf->pdev->dev,
"port dcbx_mode=%d\n", cfg->dcbx_mode);
dev_info(&pf->pdev->dev,
"port ets_cfg: willing=%d cbs=%d, maxtcs=%d\n",
cfg->etscfg.willing, cfg->etscfg.cbs,
......
......@@ -644,11 +644,19 @@ static void i40e_get_pauseparam(struct net_device *netdev,
struct i40e_pf *pf = np->vsi->back;
struct i40e_hw *hw = &pf->hw;
struct i40e_link_status *hw_link_info = &hw->phy.link_info;
struct i40e_dcbx_config *dcbx_cfg = &hw->local_dcbx_config;
pause->autoneg =
((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
AUTONEG_ENABLE : AUTONEG_DISABLE);
/* PFC enabled so report LFC as off */
if (dcbx_cfg->pfc.pfcenable) {
pause->rx_pause = 0;
pause->tx_pause = 0;
return;
}
if (hw->fc.current_mode == I40E_FC_RX_PAUSE) {
pause->rx_pause = 1;
} else if (hw->fc.current_mode == I40E_FC_TX_PAUSE) {
......@@ -672,6 +680,7 @@ static int i40e_set_pauseparam(struct net_device *netdev,
struct i40e_vsi *vsi = np->vsi;
struct i40e_hw *hw = &pf->hw;
struct i40e_link_status *hw_link_info = &hw->phy.link_info;
struct i40e_dcbx_config *dcbx_cfg = &hw->local_dcbx_config;
bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
i40e_status status;
u8 aq_failures;
......@@ -693,8 +702,9 @@ static int i40e_set_pauseparam(struct net_device *netdev,
netdev_info(netdev, "Autoneg did not complete so changing settings may not result in an actual change.\n");
}
if (hw->fc.current_mode == I40E_FC_PFC) {
netdev_info(netdev, "Priority flow control enabled. Cannot set link flow control.\n");
if (dcbx_cfg->pfc.pfcenable) {
netdev_info(netdev,
"Priority flow control enabled. Cannot set link flow control.\n");
return -EOPNOTSUPP;
}
......
......@@ -343,7 +343,7 @@ int i40e_init_pf_fcoe(struct i40e_pf *pf)
**/
u8 i40e_get_fcoe_tc_map(struct i40e_pf *pf)
{
struct i40e_ieee_app_priority_table app;
struct i40e_dcb_app_priority_table app;
struct i40e_hw *hw = &pf->hw;
u8 enabled_tc = 0;
u8 tc, i;
......
......@@ -38,8 +38,8 @@ static const char i40e_driver_string[] =
#define DRV_KERN "-k"
#define DRV_VERSION_MAJOR 1
#define DRV_VERSION_MINOR 0
#define DRV_VERSION_BUILD 21
#define DRV_VERSION_MINOR 1
#define DRV_VERSION_BUILD 23
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN
......@@ -2381,6 +2381,35 @@ static void i40e_vsi_free_rx_resources(struct i40e_vsi *vsi)
#endif
}
/**
* i40e_config_xps_tx_ring - Configure XPS for a Tx ring
* @ring: The Tx ring to configure
*
* This enables/disables XPS for a given Tx descriptor ring
* based on the TCs enabled for the VSI that ring belongs to.
**/
static void i40e_config_xps_tx_ring(struct i40e_ring *ring)
{
struct i40e_vsi *vsi = ring->vsi;
cpumask_var_t mask;
if (ring->q_vector && ring->netdev) {
/* Single TC mode enable XPS */
if (vsi->tc_config.numtc <= 1 &&
!test_and_set_bit(__I40E_TX_XPS_INIT_DONE, &ring->state)) {
netif_set_xps_queue(ring->netdev,
&ring->q_vector->affinity_mask,
ring->queue_index);
} else if (alloc_cpumask_var(&mask, GFP_KERNEL)) {
/* Disable XPS to allow selection based on TC */
bitmap_zero(cpumask_bits(mask), nr_cpumask_bits);
netif_set_xps_queue(ring->netdev, mask,
ring->queue_index);
free_cpumask_var(mask);
}
}
}
/**
* i40e_configure_tx_ring - Configure a transmit ring context and rest
* @ring: The Tx ring to configure
......@@ -2404,13 +2433,8 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring)
ring->atr_sample_rate = 0;
}
/* initialize XPS */
if (ring->q_vector && ring->netdev &&
vsi->tc_config.numtc <= 1 &&
!test_and_set_bit(__I40E_TX_XPS_INIT_DONE, &ring->state))
netif_set_xps_queue(ring->netdev,
&ring->q_vector->affinity_mask,
ring->queue_index);
/* configure XPS */
i40e_config_xps_tx_ring(ring);
/* clear the context structure first */
memset(&tx_ctx, 0, sizeof(tx_ctx));
......@@ -3492,6 +3516,9 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
}
wr32(hw, I40E_QTX_ENA(pf_q), tx_reg);
/* No waiting for the Tx queue to disable */
if (!enable && test_bit(__I40E_PORT_TX_SUSPENDED, &pf->state))
continue;
/* wait for the change to finish */
ret = i40e_pf_txq_wait(pf, pf_q, enable);
......@@ -3859,6 +3886,15 @@ static void i40e_quiesce_vsi(struct i40e_vsi *vsi)
if (test_bit(__I40E_DOWN, &vsi->state))
return;
/* No need to disable FCoE VSI when Tx suspended */
if ((test_bit(__I40E_PORT_TX_SUSPENDED, &vsi->back->state)) &&
vsi->type == I40E_VSI_FCOE) {
dev_dbg(&vsi->back->pdev->dev,
"%s: VSI seid %d skipping FCoE VSI disable\n",
__func__, vsi->seid);
return;
}
set_bit(__I40E_NEEDS_RESTART, &vsi->state);
if (vsi->netdev && netif_running(vsi->netdev)) {
vsi->netdev->netdev_ops->ndo_stop(vsi->netdev);
......@@ -3911,6 +3947,57 @@ static void i40e_pf_unquiesce_all_vsi(struct i40e_pf *pf)
}
}
#ifdef CONFIG_I40E_DCB
/**
* i40e_vsi_wait_txq_disabled - Wait for VSI's queues to be disabled
* @vsi: the VSI being configured
*
* This function waits for the given VSI's Tx queues to be disabled.
**/
static int i40e_vsi_wait_txq_disabled(struct i40e_vsi *vsi)
{
struct i40e_pf *pf = vsi->back;
int i, pf_q, ret;
pf_q = vsi->base_queue;
for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
/* Check and wait for the disable status of the queue */
ret = i40e_pf_txq_wait(pf, pf_q, false);
if (ret) {
dev_info(&pf->pdev->dev,
"%s: VSI seid %d Tx ring %d disable timeout\n",
__func__, vsi->seid, pf_q);
return ret;
}
}
return 0;
}
/**
* i40e_pf_wait_txq_disabled - Wait for all queues of PF VSIs to be disabled
* @pf: the PF
*
* This function waits for the Tx queues to be in disabled state for all the
* VSIs that are managed by this PF.
**/
static int i40e_pf_wait_txq_disabled(struct i40e_pf *pf)
{
int v, ret = 0;
for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
/* No need to wait for FCoE VSI queues */
if (pf->vsi[v] && pf->vsi[v]->type != I40E_VSI_FCOE) {
ret = i40e_vsi_wait_txq_disabled(pf->vsi[v]);
if (ret)
break;
}
}
return ret;
}
#endif
/**
* i40e_dcb_get_num_tc - Get the number of TCs from DCBx config
* @dcbcfg: the corresponding DCBx configuration structure
......@@ -4381,6 +4468,31 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf)
}
}
/**
* i40e_resume_port_tx - Resume port Tx
* @pf: PF struct
*
* Resume a port's Tx and issue a PF reset in case of failure to
* resume.
**/
static int i40e_resume_port_tx(struct i40e_pf *pf)
{
struct i40e_hw *hw = &pf->hw;
int ret;
ret = i40e_aq_resume_port_tx(hw, NULL);
if (ret) {
dev_info(&pf->pdev->dev,
"AQ command Resume Port Tx failed = %d\n",
pf->hw.aq.asq_last_status);
/* Schedule PF reset to recover */
set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
i40e_service_event_schedule(pf);
}
return ret;
}
/**
* i40e_init_pf_dcb - Initialize DCB configuration
* @pf: PF being configured
......@@ -4417,6 +4529,8 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
/* Enable DCB tagging only when more than one TC */
if (i40e_dcb_get_num_tc(&hw->local_dcbx_config) > 1)
pf->flags |= I40E_FLAG_DCB_ENABLED;
dev_dbg(&pf->pdev->dev,
"DCBX offload is supported for this PF.\n");
}
} else {
dev_info(&pf->pdev->dev, "AQ Querying DCB configuration failed: %d\n",
......@@ -4998,6 +5112,8 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
dev_dbg(&pf->pdev->dev, "APP Table change detected.\n");
}
dev_dbg(&pf->pdev->dev, "%s: need_reconfig=%d\n", __func__,
need_reconfig);
return need_reconfig;
}
......@@ -5025,11 +5141,16 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
/* Ignore if event is not for Nearest Bridge */
type = ((mib->type >> I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT)
& I40E_AQ_LLDP_BRIDGE_TYPE_MASK);
dev_dbg(&pf->pdev->dev,
"%s: LLDP event mib bridge type 0x%x\n", __func__, type);
if (type != I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE)
return ret;
/* Check MIB Type and return if event for Remote MIB update */
type = mib->type & I40E_AQ_LLDP_MIB_TYPE_MASK;
dev_dbg(&pf->pdev->dev,
"%s: LLDP event mib type %s\n", __func__,
type ? "remote" : "local");
if (type == I40E_AQ_LLDP_MIB_REMOTE) {
/* Update the remote cached instance and return */
ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
......@@ -5038,12 +5159,14 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
goto exit;
}
/* Convert/store the DCBX data from LLDPDU temporarily */
memset(&tmp_dcbx_cfg, 0, sizeof(tmp_dcbx_cfg));
ret = i40e_lldp_to_dcb_config(e->msg_buf, &tmp_dcbx_cfg);
/* Store the old configuration */
tmp_dcbx_cfg = *dcbx_cfg;
/* Get updated DCBX data from firmware */
ret = i40e_get_dcb_config(&pf->hw);
if (ret) {
/* Error in LLDPDU parsing return */
dev_info(&pf->pdev->dev, "Failed parsing LLDPDU from event buffer\n");
dev_info(&pf->pdev->dev, "Failed querying DCB configuration data from firmware.\n");
goto exit;
}
......@@ -5053,12 +5176,9 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
goto exit;
}
need_reconfig = i40e_dcb_need_reconfig(pf, dcbx_cfg, &tmp_dcbx_cfg);
i40e_dcbnl_flush_apps(pf, &tmp_dcbx_cfg);
need_reconfig = i40e_dcb_need_reconfig(pf, &tmp_dcbx_cfg, dcbx_cfg);
/* Overwrite the new configuration */
*dcbx_cfg = tmp_dcbx_cfg;
i40e_dcbnl_flush_apps(pf, dcbx_cfg);
if (!need_reconfig)
goto exit;
......@@ -5069,12 +5189,23 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
else
pf->flags &= ~I40E_FLAG_DCB_ENABLED;
set_bit(__I40E_PORT_TX_SUSPENDED, &pf->state);
/* Reconfiguration needed quiesce all VSIs */
i40e_pf_quiesce_all_vsi(pf);
/* Changes in configuration update VEB/VSI */
i40e_dcb_reconfigure(pf);
ret = i40e_resume_port_tx(pf);
clear_bit(__I40E_PORT_TX_SUSPENDED, &pf->state);
/* In case of error no point in resuming VSIs */
if (ret)
goto exit;
/* Wait for the PF's Tx queues to be disabled */
ret = i40e_pf_wait_txq_disabled(pf);
if (!ret)
i40e_pf_unquiesce_all_vsi(pf);
exit:
return ret;
......@@ -8242,6 +8373,7 @@ static int i40e_veb_get_bw_info(struct i40e_veb *veb)
veb->bw_limit = le16_to_cpu(ets_data.port_bw_limit);
veb->bw_max_quanta = ets_data.tc_bw_max;
veb->is_abs_credits = bw_data.absolute_credits_enable;
veb->enabled_tc = ets_data.tc_valid_bits;
tc_bw_max = le16_to_cpu(bw_data.tc_bw_max[0]) |
(le16_to_cpu(bw_data.tc_bw_max[1]) << 16);
for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
......
......@@ -175,6 +175,9 @@ i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_get_cee_dcb_config(struct i40e_hw *hw,
void *buff, u16 buff_size,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw,
u16 udp_port, u8 protocol_index,
u8 *filter_index,
......@@ -230,6 +233,10 @@ i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,
u16 seid,
struct i40e_aqc_query_switching_comp_bw_config_resp *bw_data,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
struct i40e_lldp_variables *lldp_cfg);
/* i40e_common */
i40e_status i40e_init_shared_code(struct i40e_hw *hw);
i40e_status i40e_pf_reset(struct i40e_hw *hw);
......
......@@ -382,11 +382,17 @@ void i40e_ptp_set_increment(struct i40e_pf *pf)
incval = I40E_PTP_1GB_INCVAL;
break;
case I40E_LINK_SPEED_100MB:
{
static int warn_once;
if (!warn_once) {
dev_warn(&pf->pdev->dev,
"%s: 1588 functionality is not supported at 100 Mbps. Stopping the PHC.\n",
__func__);
"1588 functionality is not supported at 100 Mbps. Stopping the PHC.\n");
warn_once++;
}
incval = 0;
break;
}
case I40E_LINK_SPEED_40GB:
default:
incval = I40E_PTP_40GB_INCVAL;
......
......@@ -381,9 +381,18 @@ struct i40e_fc_info {
#define I40E_MAX_USER_PRIORITY 8
#define I40E_DCBX_MAX_APPS 32
#define I40E_LLDPDU_SIZE 1500
/* IEEE 802.1Qaz ETS Configuration data */
struct i40e_ieee_ets_config {
#define I40E_TLV_STATUS_OPER 0x1
#define I40E_TLV_STATUS_SYNC 0x2
#define I40E_TLV_STATUS_ERR 0x4
#define I40E_CEE_OPER_MAX_APPS 3
#define I40E_APP_PROTOID_FCOE 0x8906
#define I40E_APP_PROTOID_ISCSI 0x0cbc
#define I40E_APP_PROTOID_FIP 0x8914
#define I40E_APP_SEL_ETHTYPE 0x1
#define I40E_APP_SEL_TCPIP 0x2
/* CEE or IEEE 802.1Qaz ETS Configuration data */
struct i40e_dcb_ets_config {
u8 willing;
u8 cbs;
u8 maxtcs;
......@@ -392,34 +401,30 @@ struct i40e_ieee_ets_config {
u8 tsatable[I40E_MAX_TRAFFIC_CLASS];
};
/* IEEE 802.1Qaz ETS Recommendation data */
struct i40e_ieee_ets_recommend {
u8 prioritytable[I40E_MAX_TRAFFIC_CLASS];
u8 tcbwtable[I40E_MAX_TRAFFIC_CLASS];
u8 tsatable[I40E_MAX_TRAFFIC_CLASS];
};
/* IEEE 802.1Qaz PFC Configuration data */
struct i40e_ieee_pfc_config {
/* CEE or IEEE 802.1Qaz PFC Configuration data */
struct i40e_dcb_pfc_config {
u8 willing;
u8 mbc;
u8 pfccap;
u8 pfcenable;
};
/* IEEE 802.1Qaz Application Priority data */
struct i40e_ieee_app_priority_table {
/* CEE or IEEE 802.1Qaz Application Priority data */
struct i40e_dcb_app_priority_table {
u8 priority;
u8 selector;
u16 protocolid;
};
struct i40e_dcbx_config {
u8 dcbx_mode;
#define I40E_DCBX_MODE_CEE 0x1
#define I40E_DCBX_MODE_IEEE 0x2
u32 numapps;
struct i40e_ieee_ets_config etscfg;
struct i40e_ieee_ets_recommend etsrec;
struct i40e_ieee_pfc_config pfc;
struct i40e_ieee_app_priority_table app[I40E_DCBX_MAX_APPS];
struct i40e_dcb_ets_config etscfg;
struct i40e_dcb_ets_config etsrec;
struct i40e_dcb_pfc_config pfc;
struct i40e_dcb_app_priority_table app[I40E_DCBX_MAX_APPS];
};
/* Port hardware description */
......@@ -1372,6 +1377,18 @@ enum i40e_reset_type {
I40E_RESET_EMPR = 3,
};
/* IEEE 802.1AB LLDP Agent Variables from NVM */
#define I40E_NVM_LLDP_CFG_PTR 0xD
struct i40e_lldp_variables {
u16 length;
u16 adminstatus;
u16 msgfasttx;
u16 msgtxinterval;
u16 txparams;
u16 timers;
u16 crc8;
};
/* RSS Hash Table Size */
#define I40E_PFQF_CTL_0_HASHLUTSIZE_512 0x00010000
#endif /* _I40E_TYPE_H_ */
......@@ -1869,6 +1869,12 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
if (!test_bit(__I40E_VFLR_EVENT_PENDING, &pf->state))
return 0;
/* re-enable vflr interrupt cause */
reg = rd32(hw, I40E_PFINT_ICR0_ENA);
reg |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
wr32(hw, I40E_PFINT_ICR0_ENA, reg);
i40e_flush(hw);
clear_bit(__I40E_VFLR_EVENT_PENDING, &pf->state);
for (vf_id = 0; vf_id < pf->num_alloc_vfs; vf_id++) {
reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
......@@ -1885,12 +1891,6 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf)
}
}
/* re-enable vflr interrupt cause */
reg = rd32(hw, I40E_PFINT_ICR0_ENA);
reg |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
wr32(hw, I40E_PFINT_ICR0_ENA, reg);
i40e_flush(hw);
return 0;
}
......
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