Commit a6a4db16 authored by Paolo Abeni's avatar Paolo Abeni
Browse files

Merge branch 'add-support-for-25g-50g-and-100g-to-fbnic'

Alexander Duyck says:

====================
Add support for 25G, 50G, and 100G to fbnic

The fbnic driver up till now had avoided actually reporting link as the
phylink setup only supported up to 40G configurations. This changeset is
meant to start addressing that by adding support for 50G and 100G interface
types.

With that basic support added fbnic can then set those types based on the
EEPROM configuration provided by the firmware and then report those speeds
out using the information provided via the phylink call for getting the
link ksettings. This provides the basic MAC support and enables supporting
the speeds as well as configuring flow control.

After this I plan to add support for a PHY that will represent the SerDes
PHY being used to manage the link as we need a way to indicate link
training into phylink to prevent link flaps on the PCS while the SerDes is
in training, and then after that I will look at rolling support for our
PCS/PMA into the XPCS driver.
====================

Link: https://patch.msgid.link/175028434031.625704.17964815932031774402.stgit@ahduyck-xeon-server.home.arpa


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents cccfe098 eb4c27ed
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1683,10 +1683,13 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
	.get_drvinfo		= fbnic_get_drvinfo,
	.get_regs_len		= fbnic_get_regs_len,
	.get_regs		= fbnic_get_regs,
	.get_link		= ethtool_op_get_link,
	.get_coalesce		= fbnic_get_coalesce,
	.set_coalesce		= fbnic_set_coalesce,
	.get_ringparam		= fbnic_get_ringparam,
	.set_ringparam		= fbnic_set_ringparam,
	.get_pauseparam		= fbnic_phylink_get_pauseparam,
	.set_pauseparam		= fbnic_phylink_set_pauseparam,
	.get_strings		= fbnic_get_strings,
	.get_ethtool_stats	= fbnic_get_ethtool_stats,
	.get_sset_count		= fbnic_get_sset_count,
@@ -1705,6 +1708,8 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
	.set_channels		= fbnic_set_channels,
	.get_ts_info		= fbnic_get_ts_info,
	.get_ts_stats		= fbnic_get_ts_stats,
	.get_link_ksettings	= fbnic_phylink_ethtool_ksettings_get,
	.get_fecparam		= fbnic_phylink_get_fecparam,
	.get_eth_mac_stats	= fbnic_get_eth_mac_stats,
	.get_eth_ctrl_stats	= fbnic_get_eth_ctrl_stats,
	.get_rmon_stats		= fbnic_get_rmon_stats,
+21 −2
Original line number Diff line number Diff line
@@ -95,6 +95,9 @@ void fbnic_mbx_init(struct fbnic_dev *fbd)
	/* Initialize lock to protect Tx ring */
	spin_lock_init(&fbd->fw_tx_lock);

	/* Reset FW Capabilities */
	memset(&fbd->fw_cap, 0, sizeof(fbd->fw_cap));

	/* Reinitialize mailbox memory */
	for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++)
		memset(&fbd->mbx[i], 0, sizeof(struct fbnic_fw_mbx));
@@ -1117,6 +1120,7 @@ void fbnic_mbx_poll(struct fbnic_dev *fbd)

int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
{
	struct fbnic_fw_mbx *tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX];
	unsigned long timeout = jiffies + 10 * HZ + 1;
	int err, i;

@@ -1149,8 +1153,23 @@ int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
	if (err)
		goto clean_mbx;

	/* Use "1" to indicate we entered the state waiting for a response */
	fbd->fw_cap.running.mgmt.version = 1;
	/* Poll until we get a current management firmware version, use "1"
	 * to indicate we entered the polling state waiting for a response
	 */
	for (fbd->fw_cap.running.mgmt.version = 1;
	     fbd->fw_cap.running.mgmt.version < MIN_FW_VERSION_CODE;) {
		if (!tx_mbx->ready)
			err = -ENODEV;
		if (err)
			goto clean_mbx;

		msleep(20);
		fbnic_mbx_poll(fbd);

		/* set err, but wait till mgmt.version check to report it */
		if (!time_is_after_jiffies(timeout))
			err = -ETIMEDOUT;
	}

	return 0;
clean_mbx:
+4 −4
Original line number Diff line number Diff line
@@ -155,10 +155,10 @@ enum {
};

enum {
	FBNIC_FW_LINK_SPEED_25R1		= 1,
	FBNIC_FW_LINK_SPEED_50R2		= 2,
	FBNIC_FW_LINK_SPEED_50R1		= 3,
	FBNIC_FW_LINK_SPEED_100R2		= 4,
	FBNIC_FW_LINK_MODE_25CR			= 1,
	FBNIC_FW_LINK_MODE_50CR2		= 2,
	FBNIC_FW_LINK_MODE_50CR			= 3,
	FBNIC_FW_LINK_MODE_100CR2		= 4,
};

enum {
+40 −55
Original line number Diff line number Diff line
@@ -452,7 +452,7 @@ static u32 __fbnic_mac_cmd_config_asic(struct fbnic_dev *fbd,
		command_config |= FBNIC_MAC_COMMAND_CONFIG_RX_PAUSE_DIS;

	/* Disable fault handling if no FEC is requested */
	if ((fbn->fec & FBNIC_FEC_MODE_MASK) == FBNIC_FEC_OFF)
	if (fbn->fec == FBNIC_FEC_OFF)
		command_config |= FBNIC_MAC_COMMAND_CONFIG_FLT_HDL_DIS;

	return command_config;
@@ -468,15 +468,15 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd)
		return false;

	/* Define the expected lane mask for the status bits we need to check */
	switch (fbn->link_mode & FBNIC_LINK_MODE_MASK) {
	case FBNIC_LINK_100R2:
	switch (fbn->aui) {
	case FBNIC_AUI_100GAUI2:
		lane_mask = 0xf;
		break;
	case FBNIC_LINK_50R1:
	case FBNIC_AUI_50GAUI1:
		lane_mask = 3;
		break;
	case FBNIC_LINK_50R2:
		switch (fbn->fec & FBNIC_FEC_MODE_MASK) {
	case FBNIC_AUI_LAUI2:
		switch (fbn->fec) {
		case FBNIC_FEC_OFF:
			lane_mask = 0x63;
			break;
@@ -488,13 +488,13 @@ static bool fbnic_mac_get_pcs_link_status(struct fbnic_dev *fbd)
			break;
		}
		break;
	case FBNIC_LINK_25R1:
	case FBNIC_AUI_25GAUI:
		lane_mask = 1;
		break;
	}

	/* Use an XOR to remove the bits we expect to see set */
	switch (fbn->fec & FBNIC_FEC_MODE_MASK) {
	switch (fbn->fec) {
	case FBNIC_FEC_OFF:
		lane_mask ^= FIELD_GET(FBNIC_SIG_PCS_OUT0_BLOCK_LOCK,
				       pcs_status);
@@ -540,53 +540,41 @@ static bool fbnic_pcs_get_link_asic(struct fbnic_dev *fbd)
	return link;
}

static void fbnic_pcs_get_fw_settings(struct fbnic_dev *fbd)
void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec)
{
	struct fbnic_net *fbn = netdev_priv(fbd->netdev);
	u8 link_mode = fbn->link_mode;
	u8 fec = fbn->fec;

	/* Update FEC first to reflect FW current mode */
	if (fbn->fec & FBNIC_FEC_AUTO) {
		switch (fbd->fw_cap.link_fec) {
		case FBNIC_FW_LINK_FEC_NONE:
			fec = FBNIC_FEC_OFF;
			break;
		case FBNIC_FW_LINK_FEC_RS:
			fec = FBNIC_FEC_RS;
	/* Retrieve default speed from FW */
	switch (fbd->fw_cap.link_speed) {
	case FBNIC_FW_LINK_MODE_25CR:
		*aui = FBNIC_AUI_25GAUI;
		break;
		case FBNIC_FW_LINK_FEC_BASER:
			fec = FBNIC_FEC_BASER;
	case FBNIC_FW_LINK_MODE_50CR2:
		*aui = FBNIC_AUI_LAUI2;
		break;
	case FBNIC_FW_LINK_MODE_50CR:
		*aui = FBNIC_AUI_50GAUI1;
		*fec = FBNIC_FEC_RS;
		return;
	case FBNIC_FW_LINK_MODE_100CR2:
		*aui = FBNIC_AUI_100GAUI2;
		*fec = FBNIC_FEC_RS;
		return;
	default:
		*aui = FBNIC_AUI_UNKNOWN;
		return;
	}

		fbn->fec = fec;
	}

	/* Do nothing if AUTO mode is not engaged */
	if (fbn->link_mode & FBNIC_LINK_AUTO) {
		switch (fbd->fw_cap.link_speed) {
		case FBNIC_FW_LINK_SPEED_25R1:
			link_mode = FBNIC_LINK_25R1;
			break;
		case FBNIC_FW_LINK_SPEED_50R2:
			link_mode = FBNIC_LINK_50R2;
	/* Update FEC first to reflect FW current mode */
	switch (fbd->fw_cap.link_fec) {
	case FBNIC_FW_LINK_FEC_NONE:
		*fec = FBNIC_FEC_OFF;
		break;
		case FBNIC_FW_LINK_SPEED_50R1:
			link_mode = FBNIC_LINK_50R1;
			fec = FBNIC_FEC_RS;
	case FBNIC_FW_LINK_FEC_RS:
	default:
		*fec = FBNIC_FEC_RS;
		break;
		case FBNIC_FW_LINK_SPEED_100R2:
			link_mode = FBNIC_LINK_100R2;
			fec = FBNIC_FEC_RS;
	case FBNIC_FW_LINK_FEC_BASER:
		*fec = FBNIC_FEC_BASER;
		break;
		default:
			return;
		}

		fbn->link_mode = link_mode;
	}
}

@@ -596,9 +584,6 @@ static int fbnic_pcs_enable_asic(struct fbnic_dev *fbd)
	wr32(fbd, FBNIC_SIG_PCS_INTR_MASK, ~0);
	wr32(fbd, FBNIC_SIG_PCS_INTR_STS, ~0);

	/* Pull in settings from FW */
	fbnic_pcs_get_fw_settings(fbd);

	return 0;
}

+10 −13
Original line number Diff line number Diff line
@@ -25,27 +25,23 @@ enum {
	FBNIC_FEC_OFF		= 0,
	FBNIC_FEC_RS		= 1,
	FBNIC_FEC_BASER		= 2,
	FBNIC_FEC_AUTO		= 4,
};

#define FBNIC_FEC_MODE_MASK	(FBNIC_FEC_AUTO - 1)

/* Treat the link modes as a set of modulation/lanes bitmask:
/* Treat the AUI modes as a modulation/lanes bitmask:
 * Bit 0: Lane Count, 0 = R1, 1 = R2
 * Bit 1: Modulation, 0 = NRZ, 1 = PAM4
 * Bit 2: Retrieve link mode from FW
 * Bit 2: Unknown Modulation/Lane Configuration
 */
enum {
	FBNIC_LINK_25R1		= 0,
	FBNIC_LINK_50R2		= 1,
	FBNIC_LINK_50R1		= 2,
	FBNIC_LINK_100R2	= 3,
	FBNIC_LINK_AUTO		= 4,
	FBNIC_AUI_25GAUI	= 0,	/* 25.7812GBd	25.78125 * 1 */
	FBNIC_AUI_LAUI2		= 1,	/* 51.5625GBd	25.78128 * 2 */
	FBNIC_AUI_50GAUI1	= 2,	/* 53.125GBd	53.125   * 1 */
	FBNIC_AUI_100GAUI2	= 3,	/* 106.25GBd	53.125   * 2 */
	FBNIC_AUI_UNKNOWN	= 4,
};

#define FBNIC_LINK_MODE_R2	(FBNIC_LINK_50R2)
#define FBNIC_LINK_MODE_PAM4	(FBNIC_LINK_50R1)
#define FBNIC_LINK_MODE_MASK	(FBNIC_LINK_AUTO - 1)
#define FBNIC_AUI_MODE_R2	(FBNIC_AUI_LAUI2)
#define FBNIC_AUI_MODE_PAM4	(FBNIC_AUI_50GAUI1)

enum fbnic_sensor_id {
	FBNIC_SENSOR_TEMP,		/* Temp in millidegrees Centigrade */
@@ -97,4 +93,5 @@ struct fbnic_mac {
};

int fbnic_mac_init(struct fbnic_dev *fbd);
void fbnic_mac_get_fw_settings(struct fbnic_dev *fbd, u8 *aui, u8 *fec);
#endif /* _FBNIC_MAC_H_ */
Loading