Commit fdc66c3d authored by David S. Miller's avatar David S. Miller
Browse files


Jeff Kirsher says:

====================
100GbE Intel Wired LAN Driver Updates 2019-11-06

This series contains updates to ice driver only.

Scott adds ethtool -m support so that we can read eeprom data on SFP/OSFP
modules.

Anirudh updates the return value to properly reflect when SRIOV is not
supported.

Md Fahad updates the driver to handle a change in the NVM, where the
boot configuration section was moved to the Preserved Field Area (PFA)
of the NVM.

Paul resolves an issue when DCBx requests non-contiguous TCs, transmit
hangs could occur, so configure a default traffic class (TC0) in these
cases to prevent traffic hangs.  Adds a print statement to notify the
user when unsupported modules are inserted.

Bruce fixes up the driver unload code flow to ensure we do not clear the
interrupt scheme until the reset is complete, otherwise a hardware error
may occur.

Dave updates the DCB initialization to set is_sw_lldp boolean when the
firmware has been detected to be in an untenable state.  This will
ensure that the firmware is in a known state.

Michal saves off the PCI state and I/O BARs address after PCI bus reset
so that after the reset, device registers can be read.  Also adds a NULL
pointer check to prevent a potential kernel panic.

Mitch resolves an issue where VF's on PF's other than 0 were not seeing
resets by using the per-PF VF ID instead of the absolute VF ID.

Krzysztof does some code cleanup to remove a unneeded wrapper and
reduces the code complexity.

Brett reduces confusion by changing the name of ice_vc_dis_vf() to
ice_vc_reset_vf() to better describe what the function is actually
doing.

v2: dropped patch 3 "ice: Add support for FW recovery mode detection"
    from the origin al series, while Ani makes changes based on
    community feedback to implement devlink into the changes.
v3: dropped patch 1 "ice: implement set_eeprom functionality" due to a
    bug found and additional changes will be needed when Ani implements
    devlink in the driver.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 64a26007 039c60c5
Loading
Loading
Loading
Loading
+33 −0
Original line number Diff line number Diff line
@@ -1044,6 +1044,10 @@ struct ice_aqc_get_link_status_data {
#define ICE_AQ_LINK_TOPO_CONFLICT	BIT(0)
#define ICE_AQ_LINK_MEDIA_CONFLICT	BIT(1)
#define ICE_AQ_LINK_TOPO_CORRUPT	BIT(2)
#define ICE_AQ_LINK_TOPO_UNREACH_PRT	BIT(4)
#define ICE_AQ_LINK_TOPO_UNDRUTIL_PRT	BIT(5)
#define ICE_AQ_LINK_TOPO_UNDRUTIL_MEDIA	BIT(6)
#define ICE_AQ_LINK_TOPO_UNSUPP_MEDIA	BIT(7)
	u8 reserved1;
	u8 link_info;
#define ICE_AQ_LINK_UP			BIT(0)	/* Link Status */
@@ -1147,6 +1151,33 @@ struct ice_aqc_set_port_id_led {
	u8 rsvd[13];
};

/* Read/Write SFF EEPROM command (indirect 0x06EE) */
struct ice_aqc_sff_eeprom {
	u8 lport_num;
	u8 lport_num_valid;
#define ICE_AQC_SFF_PORT_NUM_VALID	BIT(0)
	__le16 i2c_bus_addr;
#define ICE_AQC_SFF_I2CBUS_7BIT_M	0x7F
#define ICE_AQC_SFF_I2CBUS_10BIT_M	0x3FF
#define ICE_AQC_SFF_I2CBUS_TYPE_M	BIT(10)
#define ICE_AQC_SFF_I2CBUS_TYPE_7BIT	0
#define ICE_AQC_SFF_I2CBUS_TYPE_10BIT	ICE_AQC_SFF_I2CBUS_TYPE_M
#define ICE_AQC_SFF_SET_EEPROM_PAGE_S	11
#define ICE_AQC_SFF_SET_EEPROM_PAGE_M	(0x3 << ICE_AQC_SFF_SET_EEPROM_PAGE_S)
#define ICE_AQC_SFF_NO_PAGE_CHANGE	0
#define ICE_AQC_SFF_SET_23_ON_MISMATCH	1
#define ICE_AQC_SFF_SET_22_ON_MISMATCH	2
#define ICE_AQC_SFF_IS_WRITE		BIT(15)
	__le16 i2c_mem_addr;
	__le16 eeprom_page;
#define  ICE_AQC_SFF_EEPROM_BANK_S 0
#define  ICE_AQC_SFF_EEPROM_BANK_M (0xFF << ICE_AQC_SFF_EEPROM_BANK_S)
#define  ICE_AQC_SFF_EEPROM_PAGE_S 8
#define  ICE_AQC_SFF_EEPROM_PAGE_M (0xFF << ICE_AQC_SFF_EEPROM_PAGE_S)
	__le32 addr_high;
	__le32 addr_low;
};

/* NVM Read command (indirect 0x0701)
 * NVM Erase commands (direct 0x0702)
 * NVM Update commands (indirect 0x0703)
@@ -1618,6 +1649,7 @@ struct ice_aq_desc {
		struct ice_aqc_get_phy_caps get_phy;
		struct ice_aqc_set_phy_cfg set_phy;
		struct ice_aqc_restart_an restart_an;
		struct ice_aqc_sff_eeprom read_write_sff_param;
		struct ice_aqc_set_port_id_led set_port_id_led;
		struct ice_aqc_get_sw_cfg get_sw_conf;
		struct ice_aqc_sw_rules sw_rules;
@@ -1741,6 +1773,7 @@ enum ice_adminq_opc {
	ice_aqc_opc_set_event_mask			= 0x0613,
	ice_aqc_opc_set_mac_lb				= 0x0620,
	ice_aqc_opc_set_port_id_led			= 0x06E9,
	ice_aqc_opc_sff_eeprom				= 0x06EE,

	/* NVM commands */
	ice_aqc_opc_nvm_read				= 0x0701,
+112 −0
Original line number Diff line number Diff line
@@ -1066,6 +1066,72 @@ enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req)
	return ice_check_reset(hw);
}

/**
 * ice_get_pfa_module_tlv - Reads sub module TLV from NVM PFA
 * @hw: pointer to hardware structure
 * @module_tlv: pointer to module TLV to return
 * @module_tlv_len: pointer to module TLV length to return
 * @module_type: module type requested
 *
 * Finds the requested sub module TLV type from the Preserved Field
 * Area (PFA) and returns the TLV pointer and length. The caller can
 * use these to read the variable length TLV value.
 */
enum ice_status
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
		       u16 module_type)
{
	enum ice_status status;
	u16 pfa_len, pfa_ptr;
	u16 next_tlv;

	status = ice_read_sr_word(hw, ICE_SR_PFA_PTR, &pfa_ptr);
	if (status) {
		ice_debug(hw, ICE_DBG_INIT, "Preserved Field Array pointer.\n");
		return status;
	}
	status = ice_read_sr_word(hw, pfa_ptr, &pfa_len);
	if (status) {
		ice_debug(hw, ICE_DBG_INIT, "Failed to read PFA length.\n");
		return status;
	}
	/* Starting with first TLV after PFA length, iterate through the list
	 * of TLVs to find the requested one.
	 */
	next_tlv = pfa_ptr + 1;
	while (next_tlv < pfa_ptr + pfa_len) {
		u16 tlv_sub_module_type;
		u16 tlv_len;

		/* Read TLV type */
		status = ice_read_sr_word(hw, next_tlv, &tlv_sub_module_type);
		if (status) {
			ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV type.\n");
			break;
		}
		/* Read TLV length */
		status = ice_read_sr_word(hw, next_tlv + 1, &tlv_len);
		if (status) {
			ice_debug(hw, ICE_DBG_INIT, "Failed to read TLV length.\n");
			break;
		}
		if (tlv_sub_module_type == module_type) {
			if (tlv_len) {
				*module_tlv = next_tlv;
				*module_tlv_len = tlv_len;
				return 0;
			}
			return ICE_ERR_INVAL_SIZE;
		}
		/* Check next TLV, i.e. current TLV pointer + length + 2 words
		 * (for current TLV's type and length)
		 */
		next_tlv = next_tlv + tlv_len + 2;
	}
	/* Module does not exist */
	return ICE_ERR_DOES_NOT_EXIST;
}

/**
 * ice_copy_rxq_ctx_to_hw
 * @hw: pointer to the hardware structure
@@ -2555,6 +2621,52 @@ ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode,
	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
}

/**
 * ice_aq_sff_eeprom
 * @hw: pointer to the HW struct
 * @lport: bits [7:0] = logical port, bit [8] = logical port valid
 * @bus_addr: I2C bus address of the eeprom (typically 0xA0, 0=topo default)
 * @mem_addr: I2C offset. lower 8 bits for address, 8 upper bits zero padding.
 * @page: QSFP page
 * @set_page: set or ignore the page
 * @data: pointer to data buffer to be read/written to the I2C device.
 * @length: 1-16 for read, 1 for write.
 * @write: 0 read, 1 for write.
 * @cd: pointer to command details structure or NULL
 *
 * Read/Write SFF EEPROM (0x06EE)
 */
enum ice_status
ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
		  u16 mem_addr, u8 page, u8 set_page, u8 *data, u8 length,
		  bool write, struct ice_sq_cd *cd)
{
	struct ice_aqc_sff_eeprom *cmd;
	struct ice_aq_desc desc;
	enum ice_status status;

	if (!data || (mem_addr & 0xff00))
		return ICE_ERR_PARAM;

	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_sff_eeprom);
	cmd = &desc.params.read_write_sff_param;
	desc.flags = cpu_to_le16(ICE_AQ_FLAG_RD | ICE_AQ_FLAG_BUF);
	cmd->lport_num = (u8)(lport & 0xff);
	cmd->lport_num_valid = (u8)((lport >> 8) & 0x01);
	cmd->i2c_bus_addr = cpu_to_le16(((bus_addr >> 1) &
					 ICE_AQC_SFF_I2CBUS_7BIT_M) |
					((set_page <<
					  ICE_AQC_SFF_SET_EEPROM_PAGE_S) &
					 ICE_AQC_SFF_SET_EEPROM_PAGE_M));
	cmd->i2c_mem_addr = cpu_to_le16(mem_addr & 0xff);
	cmd->eeprom_page = cpu_to_le16((u16)page << ICE_AQC_SFF_EEPROM_PAGE_S);
	if (write)
		cmd->i2c_bus_addr |= cpu_to_le16(ICE_AQC_SFF_IS_WRITE);

	status = ice_aq_send_cmd(hw, &desc, data, length, cd);
	return status;
}

/**
 * __ice_aq_get_set_rss_lut
 * @hw: pointer to the hardware structure
+8 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include "ice.h"
#include "ice_type.h"
#include "ice_nvm.h"
#include "ice_flex_pipe.h"
#include "ice_switch.h"
#include <linux/avf/virtchnl.h>
@@ -16,6 +17,9 @@ void
ice_debug_cq(struct ice_hw *hw, u32 mask, void *desc, void *buf, u16 buf_len);
enum ice_status ice_init_hw(struct ice_hw *hw);
void ice_deinit_hw(struct ice_hw *hw);
enum ice_status
ice_get_pfa_module_tlv(struct ice_hw *hw, u16 *module_tlv, u16 *module_tlv_len,
		       u16 module_type);
enum ice_status ice_check_reset(struct ice_hw *hw);
enum ice_status ice_reset(struct ice_hw *hw, enum ice_reset_req req);
enum ice_status ice_create_all_ctrlq(struct ice_hw *hw);
@@ -117,6 +121,10 @@ ice_aq_set_mac_loopback(struct ice_hw *hw, bool ena_lpbk, struct ice_sq_cd *cd);
enum ice_status
ice_aq_set_port_id_led(struct ice_port_info *pi, bool is_orig_mode,
		       struct ice_sq_cd *cd);
enum ice_status
ice_aq_sff_eeprom(struct ice_hw *hw, u16 lport, u8 bus_addr,
		  u16 mem_addr, u8 page, u8 set_page, u8 *data, u8 length,
		  bool write, struct ice_sq_cd *cd);

enum ice_status
ice_dis_vsi_txq(struct ice_port_info *pi, u16 vsi_handle, u8 tc, u8 num_queues,
+3 −3
Original line number Diff line number Diff line
@@ -965,9 +965,9 @@ enum ice_status ice_init_dcb(struct ice_hw *hw, bool enable_mib_change)
	    pi->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) {
		/* Get current DCBX configuration */
		ret = ice_get_dcb_cfg(pi);
		pi->is_sw_lldp = (hw->adminq.sq_last_status == ICE_AQ_RC_EPERM);
		if (ret)
			return ret;
		pi->is_sw_lldp = false;
	} else if (pi->dcbx_status == ICE_DCBX_STATUS_DIS) {
		return ICE_ERR_NOT_READY;
	}
@@ -975,8 +975,8 @@ enum ice_status ice_init_dcb(struct ice_hw *hw, bool enable_mib_change)
	/* Configure the LLDP MIB change event */
	if (enable_mib_change) {
		ret = ice_aq_cfg_lldp_mib_change(hw, true, NULL);
		if (!ret)
			pi->is_sw_lldp = false;
		if (ret)
			pi->is_sw_lldp = true;
	}

	return ret;
+102 −39
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@

#include "ice_dcb_lib.h"

static void ice_pf_dcb_recfg(struct ice_pf *pf);

/**
 * ice_vsi_cfg_netdev_tc - Setup the netdev TC configuration
 * @vsi: the VSI being configured
@@ -137,42 +139,6 @@ void ice_vsi_cfg_dcb_rings(struct ice_vsi *vsi)
	}
}

/**
 * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs
 * @pf: pointer to the PF struct
 *
 * Assumed caller has already disabled all VSIs before
 * calling this function. Reconfiguring DCB based on
 * local_dcbx_cfg.
 */
static void ice_pf_dcb_recfg(struct ice_pf *pf)
{
	struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg;
	u8 tc_map = 0;
	int v, ret;

	/* Update each VSI */
	ice_for_each_vsi(pf, v) {
		if (!pf->vsi[v])
			continue;

		if (pf->vsi[v]->type == ICE_VSI_PF)
			tc_map = ice_dcb_get_ena_tc(dcbcfg);
		else
			tc_map = ICE_DFLT_TRAFFIC_CLASS;

		ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map);
		if (ret) {
			dev_err(&pf->pdev->dev,
				"Failed to config TC for VSI index: %d\n",
				pf->vsi[v]->idx);
			continue;
		}

		ice_vsi_map_rings_to_vectors(pf->vsi[v]);
	}
}

/**
 * ice_pf_dcb_cfg - Apply new DCB configuration
 * @pf: pointer to the PF struct
@@ -437,9 +403,10 @@ static int ice_dcb_init_cfg(struct ice_pf *pf, bool locked)
/**
 * ice_dcb_sw_default_config - Apply a default DCB config
 * @pf: PF to apply config to
 * @ets_willing: configure ets willing
 * @locked: was this function called with RTNL held
 */
static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked)
static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool ets_willing, bool locked)
{
	struct ice_aqc_port_ets_elem buf = { 0 };
	struct ice_dcbx_cfg *dcbcfg;
@@ -454,7 +421,7 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked)
	memset(dcbcfg, 0, sizeof(*dcbcfg));
	memset(&pi->local_dcbx_cfg, 0, sizeof(*dcbcfg));

	dcbcfg->etscfg.willing = 1;
	dcbcfg->etscfg.willing = ets_willing ? 1 : 0;
	dcbcfg->etscfg.maxtcs = hw->func_caps.common_cap.maxtc;
	dcbcfg->etscfg.tcbwtable[0] = 100;
	dcbcfg->etscfg.tsatable[0] = ICE_IEEE_TSA_ETS;
@@ -479,6 +446,102 @@ static int ice_dcb_sw_dflt_cfg(struct ice_pf *pf, bool locked)
	return ice_query_port_ets(pi, &buf, sizeof(buf), NULL);
}

/**
 * ice_dcb_tc_contig - Check that TCs are contiguous
 * @prio_table: pointer to priority table
 *
 * Check if TCs begin with TC0 and are contiguous
 */
static bool ice_dcb_tc_contig(u8 *prio_table)
{
	u8 max_tc = 0;
	int i;

	for (i = 0; i < CEE_DCBX_MAX_PRIO; i++) {
		u8 cur_tc = prio_table[i];

		if (cur_tc > max_tc)
			return false;
		else if (cur_tc == max_tc)
			max_tc++;
	}

	return true;
}

/**
 * ice_dcb_noncontig_cfg - Configure DCB for non-contiguous TCs
 * @pf: pointer to the PF struct
 *
 * If non-contiguous TCs, then configure SW DCB with TC0 and ETS non-willing
 */
static int ice_dcb_noncontig_cfg(struct ice_pf *pf)
{
	struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg;
	int ret;

	/* Configure SW DCB default with ETS non-willing */
	ret = ice_dcb_sw_dflt_cfg(pf, false, true);
	if (ret) {
		dev_err(&pf->pdev->dev,
			"Failed to set local DCB config %d\n", ret);
		return ret;
	}

	/* Reconfigure with ETS willing so that FW will send LLDP MIB event */
	dcbcfg->etscfg.willing = 1;
	ret = ice_set_dcb_cfg(pf->hw.port_info);
	if (ret)
		dev_err(&pf->pdev->dev, "Failed to set DCB to unwilling\n");

	return ret;
}

/**
 * ice_pf_dcb_recfg - Reconfigure all VEBs and VSIs
 * @pf: pointer to the PF struct
 *
 * Assumed caller has already disabled all VSIs before
 * calling this function. Reconfiguring DCB based on
 * local_dcbx_cfg.
 */
static void ice_pf_dcb_recfg(struct ice_pf *pf)
{
	struct ice_dcbx_cfg *dcbcfg = &pf->hw.port_info->local_dcbx_cfg;
	u8 tc_map = 0;
	int v, ret;

	/* Update each VSI */
	ice_for_each_vsi(pf, v) {
		if (!pf->vsi[v])
			continue;

		if (pf->vsi[v]->type == ICE_VSI_PF) {
			tc_map = ice_dcb_get_ena_tc(dcbcfg);

			/* If DCBX request non-contiguous TC, then configure
			 * default TC
			 */
			if (!ice_dcb_tc_contig(dcbcfg->etscfg.prio_table)) {
				tc_map = ICE_DFLT_TRAFFIC_CLASS;
				ice_dcb_noncontig_cfg(pf);
			}
		} else {
			tc_map = ICE_DFLT_TRAFFIC_CLASS;
		}

		ret = ice_vsi_cfg_tc(pf->vsi[v], tc_map);
		if (ret) {
			dev_err(&pf->pdev->dev,
				"Failed to config TC for VSI index: %d\n",
				pf->vsi[v]->idx);
			continue;
		}

		ice_vsi_map_rings_to_vectors(pf->vsi[v]);
	}
}

/**
 * ice_init_pf_dcb - initialize DCB for a PF
 * @pf: PF to initialize DCB for
@@ -507,7 +570,7 @@ int ice_init_pf_dcb(struct ice_pf *pf, bool locked)
		dev_info(&pf->pdev->dev,
			 "FW LLDP is disabled, DCBx/LLDP in SW mode.\n");
		clear_bit(ICE_FLAG_FW_LLDP_AGENT, pf->flags);
		err = ice_dcb_sw_dflt_cfg(pf, locked);
		err = ice_dcb_sw_dflt_cfg(pf, true, locked);
		if (err) {
			dev_err(&pf->pdev->dev,
				"Failed to set local DCB config %d\n", err);
Loading