162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright(c) 2015, 2016 Intel Corporation.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/firmware.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "hfi.h"
962306a36Sopenharmony_ci#include "efivar.h"
1062306a36Sopenharmony_ci#include "eprom.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define DEFAULT_PLATFORM_CONFIG_NAME "hfi1_platform.dat"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic int validate_scratch_checksum(struct hfi1_devdata *dd)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	u64 checksum = 0, temp_scratch = 0;
1762306a36Sopenharmony_ci	int i, j, version;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH);
2062306a36Sopenharmony_ci	version = (temp_scratch & BITMAP_VERSION_SMASK) >> BITMAP_VERSION_SHIFT;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	/* Prevent power on default of all zeroes from passing checksum */
2362306a36Sopenharmony_ci	if (!version) {
2462306a36Sopenharmony_ci		dd_dev_err(dd, "%s: Config bitmap uninitialized\n", __func__);
2562306a36Sopenharmony_ci		dd_dev_err(dd,
2662306a36Sopenharmony_ci			   "%s: Please update your BIOS to support active channels\n",
2762306a36Sopenharmony_ci			   __func__);
2862306a36Sopenharmony_ci		return 0;
2962306a36Sopenharmony_ci	}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	/*
3262306a36Sopenharmony_ci	 * ASIC scratch 0 only contains the checksum and bitmap version as
3362306a36Sopenharmony_ci	 * fields of interest, both of which are handled separately from the
3462306a36Sopenharmony_ci	 * loop below, so skip it
3562306a36Sopenharmony_ci	 */
3662306a36Sopenharmony_ci	checksum += version;
3762306a36Sopenharmony_ci	for (i = 1; i < ASIC_NUM_SCRATCH; i++) {
3862306a36Sopenharmony_ci		temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH + (8 * i));
3962306a36Sopenharmony_ci		for (j = sizeof(u64); j != 0; j -= 2) {
4062306a36Sopenharmony_ci			checksum += (temp_scratch & 0xFFFF);
4162306a36Sopenharmony_ci			temp_scratch >>= 16;
4262306a36Sopenharmony_ci		}
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	while (checksum >> 16)
4662306a36Sopenharmony_ci		checksum = (checksum & CHECKSUM_MASK) + (checksum >> 16);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH);
4962306a36Sopenharmony_ci	temp_scratch &= CHECKSUM_SMASK;
5062306a36Sopenharmony_ci	temp_scratch >>= CHECKSUM_SHIFT;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	if (checksum + temp_scratch == 0xFFFF)
5362306a36Sopenharmony_ci		return 1;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	dd_dev_err(dd, "%s: Configuration bitmap corrupted\n", __func__);
5662306a36Sopenharmony_ci	return 0;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void save_platform_config_fields(struct hfi1_devdata *dd)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	struct hfi1_pportdata *ppd = dd->pport;
6262306a36Sopenharmony_ci	u64 temp_scratch = 0, temp_dest = 0;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH_1);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	temp_dest = temp_scratch &
6762306a36Sopenharmony_ci		    (dd->hfi1_id ? PORT1_PORT_TYPE_SMASK :
6862306a36Sopenharmony_ci		     PORT0_PORT_TYPE_SMASK);
6962306a36Sopenharmony_ci	ppd->port_type = temp_dest >>
7062306a36Sopenharmony_ci			 (dd->hfi1_id ? PORT1_PORT_TYPE_SHIFT :
7162306a36Sopenharmony_ci			  PORT0_PORT_TYPE_SHIFT);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	temp_dest = temp_scratch &
7462306a36Sopenharmony_ci		    (dd->hfi1_id ? PORT1_LOCAL_ATTEN_SMASK :
7562306a36Sopenharmony_ci		     PORT0_LOCAL_ATTEN_SMASK);
7662306a36Sopenharmony_ci	ppd->local_atten = temp_dest >>
7762306a36Sopenharmony_ci			   (dd->hfi1_id ? PORT1_LOCAL_ATTEN_SHIFT :
7862306a36Sopenharmony_ci			    PORT0_LOCAL_ATTEN_SHIFT);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	temp_dest = temp_scratch &
8162306a36Sopenharmony_ci		    (dd->hfi1_id ? PORT1_REMOTE_ATTEN_SMASK :
8262306a36Sopenharmony_ci		     PORT0_REMOTE_ATTEN_SMASK);
8362306a36Sopenharmony_ci	ppd->remote_atten = temp_dest >>
8462306a36Sopenharmony_ci			    (dd->hfi1_id ? PORT1_REMOTE_ATTEN_SHIFT :
8562306a36Sopenharmony_ci			     PORT0_REMOTE_ATTEN_SHIFT);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	temp_dest = temp_scratch &
8862306a36Sopenharmony_ci		    (dd->hfi1_id ? PORT1_DEFAULT_ATTEN_SMASK :
8962306a36Sopenharmony_ci		     PORT0_DEFAULT_ATTEN_SMASK);
9062306a36Sopenharmony_ci	ppd->default_atten = temp_dest >>
9162306a36Sopenharmony_ci			     (dd->hfi1_id ? PORT1_DEFAULT_ATTEN_SHIFT :
9262306a36Sopenharmony_ci			      PORT0_DEFAULT_ATTEN_SHIFT);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	temp_scratch = read_csr(dd, dd->hfi1_id ? ASIC_CFG_SCRATCH_3 :
9562306a36Sopenharmony_ci				ASIC_CFG_SCRATCH_2);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	ppd->tx_preset_eq = (temp_scratch & TX_EQ_SMASK) >> TX_EQ_SHIFT;
9862306a36Sopenharmony_ci	ppd->tx_preset_noeq = (temp_scratch & TX_NO_EQ_SMASK) >> TX_NO_EQ_SHIFT;
9962306a36Sopenharmony_ci	ppd->rx_preset = (temp_scratch & RX_SMASK) >> RX_SHIFT;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	ppd->max_power_class = (temp_scratch & QSFP_MAX_POWER_SMASK) >>
10262306a36Sopenharmony_ci				QSFP_MAX_POWER_SHIFT;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	ppd->config_from_scratch = true;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_civoid get_platform_config(struct hfi1_devdata *dd)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	int ret = 0;
11062306a36Sopenharmony_ci	u8 *temp_platform_config = NULL;
11162306a36Sopenharmony_ci	u32 esize;
11262306a36Sopenharmony_ci	const struct firmware *platform_config_file = NULL;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (is_integrated(dd)) {
11562306a36Sopenharmony_ci		if (validate_scratch_checksum(dd)) {
11662306a36Sopenharmony_ci			save_platform_config_fields(dd);
11762306a36Sopenharmony_ci			return;
11862306a36Sopenharmony_ci		}
11962306a36Sopenharmony_ci	} else {
12062306a36Sopenharmony_ci		ret = eprom_read_platform_config(dd,
12162306a36Sopenharmony_ci						 (void **)&temp_platform_config,
12262306a36Sopenharmony_ci						 &esize);
12362306a36Sopenharmony_ci		if (!ret) {
12462306a36Sopenharmony_ci			/* success */
12562306a36Sopenharmony_ci			dd->platform_config.data = temp_platform_config;
12662306a36Sopenharmony_ci			dd->platform_config.size = esize;
12762306a36Sopenharmony_ci			return;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci	dd_dev_err(dd,
13162306a36Sopenharmony_ci		   "%s: Failed to get platform config, falling back to sub-optimal default file\n",
13262306a36Sopenharmony_ci		   __func__);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	ret = request_firmware(&platform_config_file,
13562306a36Sopenharmony_ci			       DEFAULT_PLATFORM_CONFIG_NAME,
13662306a36Sopenharmony_ci			       &dd->pcidev->dev);
13762306a36Sopenharmony_ci	if (ret) {
13862306a36Sopenharmony_ci		dd_dev_err(dd,
13962306a36Sopenharmony_ci			   "%s: No default platform config file found\n",
14062306a36Sopenharmony_ci			   __func__);
14162306a36Sopenharmony_ci		return;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/*
14562306a36Sopenharmony_ci	 * Allocate separate memory block to store data and free firmware
14662306a36Sopenharmony_ci	 * structure. This allows free_platform_config to treat EPROM and
14762306a36Sopenharmony_ci	 * fallback configs in the same manner.
14862306a36Sopenharmony_ci	 */
14962306a36Sopenharmony_ci	dd->platform_config.data = kmemdup(platform_config_file->data,
15062306a36Sopenharmony_ci					   platform_config_file->size,
15162306a36Sopenharmony_ci					   GFP_KERNEL);
15262306a36Sopenharmony_ci	dd->platform_config.size = platform_config_file->size;
15362306a36Sopenharmony_ci	release_firmware(platform_config_file);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_civoid free_platform_config(struct hfi1_devdata *dd)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	/* Release memory allocated for eprom or fallback file read. */
15962306a36Sopenharmony_ci	kfree(dd->platform_config.data);
16062306a36Sopenharmony_ci	dd->platform_config.data = NULL;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_civoid get_port_type(struct hfi1_pportdata *ppd)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	int ret;
16662306a36Sopenharmony_ci	u32 temp;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	ret = get_platform_config_field(ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
16962306a36Sopenharmony_ci					PORT_TABLE_PORT_TYPE, &temp,
17062306a36Sopenharmony_ci					4);
17162306a36Sopenharmony_ci	if (ret) {
17262306a36Sopenharmony_ci		ppd->port_type = PORT_TYPE_UNKNOWN;
17362306a36Sopenharmony_ci		return;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci	ppd->port_type = temp;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ciint set_qsfp_tx(struct hfi1_pportdata *ppd, int on)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	u8 tx_ctrl_byte = on ? 0x0 : 0xF;
18162306a36Sopenharmony_ci	int ret = 0;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	ret = qsfp_write(ppd, ppd->dd->hfi1_id, QSFP_TX_CTRL_BYTE_OFFS,
18462306a36Sopenharmony_ci			 &tx_ctrl_byte, 1);
18562306a36Sopenharmony_ci	/* we expected 1, so consider 0 an error */
18662306a36Sopenharmony_ci	if (ret == 0)
18762306a36Sopenharmony_ci		ret = -EIO;
18862306a36Sopenharmony_ci	else if (ret == 1)
18962306a36Sopenharmony_ci		ret = 0;
19062306a36Sopenharmony_ci	return ret;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_cistatic int qual_power(struct hfi1_pportdata *ppd)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	u32 cable_power_class = 0, power_class_max = 0;
19662306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
19762306a36Sopenharmony_ci	int ret = 0;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	ret = get_platform_config_field(
20062306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_SYSTEM_TABLE, 0,
20162306a36Sopenharmony_ci		SYSTEM_TABLE_QSFP_POWER_CLASS_MAX, &power_class_max, 4);
20262306a36Sopenharmony_ci	if (ret)
20362306a36Sopenharmony_ci		return ret;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	cable_power_class = get_qsfp_power_class(cache[QSFP_MOD_PWR_OFFS]);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (cable_power_class > power_class_max)
20862306a36Sopenharmony_ci		ppd->offline_disabled_reason =
20962306a36Sopenharmony_ci			HFI1_ODR_MASK(OPA_LINKDOWN_REASON_POWER_POLICY);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (ppd->offline_disabled_reason ==
21262306a36Sopenharmony_ci			HFI1_ODR_MASK(OPA_LINKDOWN_REASON_POWER_POLICY)) {
21362306a36Sopenharmony_ci		dd_dev_err(
21462306a36Sopenharmony_ci			ppd->dd,
21562306a36Sopenharmony_ci			"%s: Port disabled due to system power restrictions\n",
21662306a36Sopenharmony_ci			__func__);
21762306a36Sopenharmony_ci		ret = -EPERM;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci	return ret;
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_cistatic int qual_bitrate(struct hfi1_pportdata *ppd)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	u16 lss = ppd->link_speed_supported, lse = ppd->link_speed_enabled;
22562306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if ((lss & OPA_LINK_SPEED_25G) && (lse & OPA_LINK_SPEED_25G) &&
22862306a36Sopenharmony_ci	    cache[QSFP_NOM_BIT_RATE_250_OFFS] < 0x64)
22962306a36Sopenharmony_ci		ppd->offline_disabled_reason =
23062306a36Sopenharmony_ci			   HFI1_ODR_MASK(OPA_LINKDOWN_REASON_LINKSPEED_POLICY);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if ((lss & OPA_LINK_SPEED_12_5G) && (lse & OPA_LINK_SPEED_12_5G) &&
23362306a36Sopenharmony_ci	    cache[QSFP_NOM_BIT_RATE_100_OFFS] < 0x7D)
23462306a36Sopenharmony_ci		ppd->offline_disabled_reason =
23562306a36Sopenharmony_ci			   HFI1_ODR_MASK(OPA_LINKDOWN_REASON_LINKSPEED_POLICY);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (ppd->offline_disabled_reason ==
23862306a36Sopenharmony_ci			HFI1_ODR_MASK(OPA_LINKDOWN_REASON_LINKSPEED_POLICY)) {
23962306a36Sopenharmony_ci		dd_dev_err(
24062306a36Sopenharmony_ci			ppd->dd,
24162306a36Sopenharmony_ci			"%s: Cable failed bitrate check, disabling port\n",
24262306a36Sopenharmony_ci			__func__);
24362306a36Sopenharmony_ci		return -EPERM;
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci	return 0;
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int set_qsfp_high_power(struct hfi1_pportdata *ppd)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	u8 cable_power_class = 0, power_ctrl_byte = 0;
25162306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
25262306a36Sopenharmony_ci	int ret;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	cable_power_class = get_qsfp_power_class(cache[QSFP_MOD_PWR_OFFS]);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	if (cable_power_class > QSFP_POWER_CLASS_1) {
25762306a36Sopenharmony_ci		power_ctrl_byte = cache[QSFP_PWR_CTRL_BYTE_OFFS];
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		power_ctrl_byte |= 1;
26062306a36Sopenharmony_ci		power_ctrl_byte &= ~(0x2);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		ret = qsfp_write(ppd, ppd->dd->hfi1_id,
26362306a36Sopenharmony_ci				 QSFP_PWR_CTRL_BYTE_OFFS,
26462306a36Sopenharmony_ci				 &power_ctrl_byte, 1);
26562306a36Sopenharmony_ci		if (ret != 1)
26662306a36Sopenharmony_ci			return -EIO;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		if (cable_power_class > QSFP_POWER_CLASS_4) {
26962306a36Sopenharmony_ci			power_ctrl_byte |= (1 << 2);
27062306a36Sopenharmony_ci			ret = qsfp_write(ppd, ppd->dd->hfi1_id,
27162306a36Sopenharmony_ci					 QSFP_PWR_CTRL_BYTE_OFFS,
27262306a36Sopenharmony_ci					 &power_ctrl_byte, 1);
27362306a36Sopenharmony_ci			if (ret != 1)
27462306a36Sopenharmony_ci				return -EIO;
27562306a36Sopenharmony_ci		}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci		/* SFF 8679 rev 1.7 LPMode Deassert time */
27862306a36Sopenharmony_ci		msleep(300);
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	return 0;
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic void apply_rx_cdr(struct hfi1_pportdata *ppd,
28462306a36Sopenharmony_ci			 u32 rx_preset_index,
28562306a36Sopenharmony_ci			 u8 *cdr_ctrl_byte)
28662306a36Sopenharmony_ci{
28762306a36Sopenharmony_ci	u32 rx_preset;
28862306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
28962306a36Sopenharmony_ci	int cable_power_class;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (!((cache[QSFP_MOD_PWR_OFFS] & 0x4) &&
29262306a36Sopenharmony_ci	      (cache[QSFP_CDR_INFO_OFFS] & 0x40)))
29362306a36Sopenharmony_ci		return;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/* RX CDR present, bypass supported */
29662306a36Sopenharmony_ci	cable_power_class = get_qsfp_power_class(cache[QSFP_MOD_PWR_OFFS]);
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (cable_power_class <= QSFP_POWER_CLASS_3) {
29962306a36Sopenharmony_ci		/* Power class <= 3, ignore config & turn RX CDR on */
30062306a36Sopenharmony_ci		*cdr_ctrl_byte |= 0xF;
30162306a36Sopenharmony_ci		return;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	get_platform_config_field(
30562306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_RX_PRESET_TABLE,
30662306a36Sopenharmony_ci		rx_preset_index, RX_PRESET_TABLE_QSFP_RX_CDR_APPLY,
30762306a36Sopenharmony_ci		&rx_preset, 4);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	if (!rx_preset) {
31062306a36Sopenharmony_ci		dd_dev_info(
31162306a36Sopenharmony_ci			ppd->dd,
31262306a36Sopenharmony_ci			"%s: RX_CDR_APPLY is set to disabled\n",
31362306a36Sopenharmony_ci			__func__);
31462306a36Sopenharmony_ci		return;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci	get_platform_config_field(
31762306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_RX_PRESET_TABLE,
31862306a36Sopenharmony_ci		rx_preset_index, RX_PRESET_TABLE_QSFP_RX_CDR,
31962306a36Sopenharmony_ci		&rx_preset, 4);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	/* Expand cdr setting to all 4 lanes */
32262306a36Sopenharmony_ci	rx_preset = (rx_preset | (rx_preset << 1) |
32362306a36Sopenharmony_ci			(rx_preset << 2) | (rx_preset << 3));
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	if (rx_preset) {
32662306a36Sopenharmony_ci		*cdr_ctrl_byte |= rx_preset;
32762306a36Sopenharmony_ci	} else {
32862306a36Sopenharmony_ci		*cdr_ctrl_byte &= rx_preset;
32962306a36Sopenharmony_ci		/* Preserve current TX CDR status */
33062306a36Sopenharmony_ci		*cdr_ctrl_byte |= (cache[QSFP_CDR_CTRL_BYTE_OFFS] & 0xF0);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void apply_tx_cdr(struct hfi1_pportdata *ppd,
33562306a36Sopenharmony_ci			 u32 tx_preset_index,
33662306a36Sopenharmony_ci			 u8 *cdr_ctrl_byte)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	u32 tx_preset;
33962306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
34062306a36Sopenharmony_ci	int cable_power_class;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (!((cache[QSFP_MOD_PWR_OFFS] & 0x8) &&
34362306a36Sopenharmony_ci	      (cache[QSFP_CDR_INFO_OFFS] & 0x80)))
34462306a36Sopenharmony_ci		return;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	/* TX CDR present, bypass supported */
34762306a36Sopenharmony_ci	cable_power_class = get_qsfp_power_class(cache[QSFP_MOD_PWR_OFFS]);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	if (cable_power_class <= QSFP_POWER_CLASS_3) {
35062306a36Sopenharmony_ci		/* Power class <= 3, ignore config & turn TX CDR on */
35162306a36Sopenharmony_ci		*cdr_ctrl_byte |= 0xF0;
35262306a36Sopenharmony_ci		return;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	get_platform_config_field(
35662306a36Sopenharmony_ci		ppd->dd,
35762306a36Sopenharmony_ci		PLATFORM_CONFIG_TX_PRESET_TABLE, tx_preset_index,
35862306a36Sopenharmony_ci		TX_PRESET_TABLE_QSFP_TX_CDR_APPLY, &tx_preset, 4);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	if (!tx_preset) {
36162306a36Sopenharmony_ci		dd_dev_info(
36262306a36Sopenharmony_ci			ppd->dd,
36362306a36Sopenharmony_ci			"%s: TX_CDR_APPLY is set to disabled\n",
36462306a36Sopenharmony_ci			__func__);
36562306a36Sopenharmony_ci		return;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci	get_platform_config_field(
36862306a36Sopenharmony_ci		ppd->dd,
36962306a36Sopenharmony_ci		PLATFORM_CONFIG_TX_PRESET_TABLE,
37062306a36Sopenharmony_ci		tx_preset_index,
37162306a36Sopenharmony_ci		TX_PRESET_TABLE_QSFP_TX_CDR, &tx_preset, 4);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* Expand cdr setting to all 4 lanes */
37462306a36Sopenharmony_ci	tx_preset = (tx_preset | (tx_preset << 1) |
37562306a36Sopenharmony_ci			(tx_preset << 2) | (tx_preset << 3));
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (tx_preset)
37862306a36Sopenharmony_ci		*cdr_ctrl_byte |= (tx_preset << 4);
37962306a36Sopenharmony_ci	else
38062306a36Sopenharmony_ci		/* Preserve current/determined RX CDR status */
38162306a36Sopenharmony_ci		*cdr_ctrl_byte &= ((tx_preset << 4) | 0xF);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void apply_cdr_settings(
38562306a36Sopenharmony_ci		struct hfi1_pportdata *ppd, u32 rx_preset_index,
38662306a36Sopenharmony_ci		u32 tx_preset_index)
38762306a36Sopenharmony_ci{
38862306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
38962306a36Sopenharmony_ci	u8 cdr_ctrl_byte = cache[QSFP_CDR_CTRL_BYTE_OFFS];
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	apply_rx_cdr(ppd, rx_preset_index, &cdr_ctrl_byte);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	apply_tx_cdr(ppd, tx_preset_index, &cdr_ctrl_byte);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	qsfp_write(ppd, ppd->dd->hfi1_id, QSFP_CDR_CTRL_BYTE_OFFS,
39662306a36Sopenharmony_ci		   &cdr_ctrl_byte, 1);
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic void apply_tx_eq_auto(struct hfi1_pportdata *ppd)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
40262306a36Sopenharmony_ci	u8 tx_eq;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (!(cache[QSFP_EQ_INFO_OFFS] & 0x8))
40562306a36Sopenharmony_ci		return;
40662306a36Sopenharmony_ci	/* Disable adaptive TX EQ if present */
40762306a36Sopenharmony_ci	tx_eq = cache[(128 * 3) + 241];
40862306a36Sopenharmony_ci	tx_eq &= 0xF0;
40962306a36Sopenharmony_ci	qsfp_write(ppd, ppd->dd->hfi1_id, (256 * 3) + 241, &tx_eq, 1);
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic void apply_tx_eq_prog(struct hfi1_pportdata *ppd, u32 tx_preset_index)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
41562306a36Sopenharmony_ci	u32 tx_preset;
41662306a36Sopenharmony_ci	u8 tx_eq;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (!(cache[QSFP_EQ_INFO_OFFS] & 0x4))
41962306a36Sopenharmony_ci		return;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	get_platform_config_field(
42262306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_TX_PRESET_TABLE,
42362306a36Sopenharmony_ci		tx_preset_index, TX_PRESET_TABLE_QSFP_TX_EQ_APPLY,
42462306a36Sopenharmony_ci		&tx_preset, 4);
42562306a36Sopenharmony_ci	if (!tx_preset) {
42662306a36Sopenharmony_ci		dd_dev_info(
42762306a36Sopenharmony_ci			ppd->dd,
42862306a36Sopenharmony_ci			"%s: TX_EQ_APPLY is set to disabled\n",
42962306a36Sopenharmony_ci			__func__);
43062306a36Sopenharmony_ci		return;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci	get_platform_config_field(
43362306a36Sopenharmony_ci			ppd->dd, PLATFORM_CONFIG_TX_PRESET_TABLE,
43462306a36Sopenharmony_ci			tx_preset_index, TX_PRESET_TABLE_QSFP_TX_EQ,
43562306a36Sopenharmony_ci			&tx_preset, 4);
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (((cache[(128 * 3) + 224] & 0xF0) >> 4) < tx_preset) {
43862306a36Sopenharmony_ci		dd_dev_info(
43962306a36Sopenharmony_ci			ppd->dd,
44062306a36Sopenharmony_ci			"%s: TX EQ %x unsupported\n",
44162306a36Sopenharmony_ci			__func__, tx_preset);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		dd_dev_info(
44462306a36Sopenharmony_ci			ppd->dd,
44562306a36Sopenharmony_ci			"%s: Applying EQ %x\n",
44662306a36Sopenharmony_ci			__func__, cache[608] & 0xF0);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci		tx_preset = (cache[608] & 0xF0) >> 4;
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	tx_eq = tx_preset | (tx_preset << 4);
45262306a36Sopenharmony_ci	qsfp_write(ppd, ppd->dd->hfi1_id, (256 * 3) + 234, &tx_eq, 1);
45362306a36Sopenharmony_ci	qsfp_write(ppd, ppd->dd->hfi1_id, (256 * 3) + 235, &tx_eq, 1);
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic void apply_rx_eq_emp(struct hfi1_pportdata *ppd, u32 rx_preset_index)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	u32 rx_preset;
45962306a36Sopenharmony_ci	u8 rx_eq, *cache = ppd->qsfp_info.cache;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (!(cache[QSFP_EQ_INFO_OFFS] & 0x2))
46262306a36Sopenharmony_ci		return;
46362306a36Sopenharmony_ci	get_platform_config_field(
46462306a36Sopenharmony_ci			ppd->dd, PLATFORM_CONFIG_RX_PRESET_TABLE,
46562306a36Sopenharmony_ci			rx_preset_index, RX_PRESET_TABLE_QSFP_RX_EMP_APPLY,
46662306a36Sopenharmony_ci			&rx_preset, 4);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	if (!rx_preset) {
46962306a36Sopenharmony_ci		dd_dev_info(
47062306a36Sopenharmony_ci			ppd->dd,
47162306a36Sopenharmony_ci			"%s: RX_EMP_APPLY is set to disabled\n",
47262306a36Sopenharmony_ci			__func__);
47362306a36Sopenharmony_ci		return;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci	get_platform_config_field(
47662306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_RX_PRESET_TABLE,
47762306a36Sopenharmony_ci		rx_preset_index, RX_PRESET_TABLE_QSFP_RX_EMP,
47862306a36Sopenharmony_ci		&rx_preset, 4);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if ((cache[(128 * 3) + 224] & 0xF) < rx_preset) {
48162306a36Sopenharmony_ci		dd_dev_info(
48262306a36Sopenharmony_ci			ppd->dd,
48362306a36Sopenharmony_ci			"%s: Requested RX EMP %x\n",
48462306a36Sopenharmony_ci			__func__, rx_preset);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci		dd_dev_info(
48762306a36Sopenharmony_ci			ppd->dd,
48862306a36Sopenharmony_ci			"%s: Applying supported EMP %x\n",
48962306a36Sopenharmony_ci			__func__, cache[608] & 0xF);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci		rx_preset = cache[608] & 0xF;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	rx_eq = rx_preset | (rx_preset << 4);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	qsfp_write(ppd, ppd->dd->hfi1_id, (256 * 3) + 236, &rx_eq, 1);
49762306a36Sopenharmony_ci	qsfp_write(ppd, ppd->dd->hfi1_id, (256 * 3) + 237, &rx_eq, 1);
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic void apply_eq_settings(struct hfi1_pportdata *ppd,
50162306a36Sopenharmony_ci			      u32 rx_preset_index, u32 tx_preset_index)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* no point going on w/o a page 3 */
50662306a36Sopenharmony_ci	if (cache[2] & 4) {
50762306a36Sopenharmony_ci		dd_dev_info(ppd->dd,
50862306a36Sopenharmony_ci			    "%s: Upper page 03 not present\n",
50962306a36Sopenharmony_ci			    __func__);
51062306a36Sopenharmony_ci		return;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	apply_tx_eq_auto(ppd);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	apply_tx_eq_prog(ppd, tx_preset_index);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	apply_rx_eq_emp(ppd, rx_preset_index);
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic void apply_rx_amplitude_settings(
52162306a36Sopenharmony_ci		struct hfi1_pportdata *ppd, u32 rx_preset_index,
52262306a36Sopenharmony_ci		u32 tx_preset_index)
52362306a36Sopenharmony_ci{
52462306a36Sopenharmony_ci	u32 rx_preset;
52562306a36Sopenharmony_ci	u8 rx_amp = 0, i = 0, preferred = 0, *cache = ppd->qsfp_info.cache;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	/* no point going on w/o a page 3 */
52862306a36Sopenharmony_ci	if (cache[2] & 4) {
52962306a36Sopenharmony_ci		dd_dev_info(ppd->dd,
53062306a36Sopenharmony_ci			    "%s: Upper page 03 not present\n",
53162306a36Sopenharmony_ci			    __func__);
53262306a36Sopenharmony_ci		return;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci	if (!(cache[QSFP_EQ_INFO_OFFS] & 0x1)) {
53562306a36Sopenharmony_ci		dd_dev_info(ppd->dd,
53662306a36Sopenharmony_ci			    "%s: RX_AMP_APPLY is set to disabled\n",
53762306a36Sopenharmony_ci			    __func__);
53862306a36Sopenharmony_ci		return;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	get_platform_config_field(ppd->dd,
54262306a36Sopenharmony_ci				  PLATFORM_CONFIG_RX_PRESET_TABLE,
54362306a36Sopenharmony_ci				  rx_preset_index,
54462306a36Sopenharmony_ci				  RX_PRESET_TABLE_QSFP_RX_AMP_APPLY,
54562306a36Sopenharmony_ci				  &rx_preset, 4);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	if (!rx_preset) {
54862306a36Sopenharmony_ci		dd_dev_info(ppd->dd,
54962306a36Sopenharmony_ci			    "%s: RX_AMP_APPLY is set to disabled\n",
55062306a36Sopenharmony_ci			    __func__);
55162306a36Sopenharmony_ci		return;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci	get_platform_config_field(ppd->dd,
55462306a36Sopenharmony_ci				  PLATFORM_CONFIG_RX_PRESET_TABLE,
55562306a36Sopenharmony_ci				  rx_preset_index,
55662306a36Sopenharmony_ci				  RX_PRESET_TABLE_QSFP_RX_AMP,
55762306a36Sopenharmony_ci				  &rx_preset, 4);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	dd_dev_info(ppd->dd,
56062306a36Sopenharmony_ci		    "%s: Requested RX AMP %x\n",
56162306a36Sopenharmony_ci		    __func__,
56262306a36Sopenharmony_ci		    rx_preset);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
56562306a36Sopenharmony_ci		if (cache[(128 * 3) + 225] & (1 << i)) {
56662306a36Sopenharmony_ci			preferred = i;
56762306a36Sopenharmony_ci			if (preferred == rx_preset)
56862306a36Sopenharmony_ci				break;
56962306a36Sopenharmony_ci		}
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/*
57362306a36Sopenharmony_ci	 * Verify that preferred RX amplitude is not just a
57462306a36Sopenharmony_ci	 * fall through of the default
57562306a36Sopenharmony_ci	 */
57662306a36Sopenharmony_ci	if (!preferred && !(cache[(128 * 3) + 225] & 0x1)) {
57762306a36Sopenharmony_ci		dd_dev_info(ppd->dd, "No supported RX AMP, not applying\n");
57862306a36Sopenharmony_ci		return;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	dd_dev_info(ppd->dd,
58262306a36Sopenharmony_ci		    "%s: Applying RX AMP %x\n", __func__, preferred);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	rx_amp = preferred | (preferred << 4);
58562306a36Sopenharmony_ci	qsfp_write(ppd, ppd->dd->hfi1_id, (256 * 3) + 238, &rx_amp, 1);
58662306a36Sopenharmony_ci	qsfp_write(ppd, ppd->dd->hfi1_id, (256 * 3) + 239, &rx_amp, 1);
58762306a36Sopenharmony_ci}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci#define OPA_INVALID_INDEX 0xFFF
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_cistatic void apply_tx_lanes(struct hfi1_pportdata *ppd, u8 field_id,
59262306a36Sopenharmony_ci			   u32 config_data, const char *message)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	u8 i;
59562306a36Sopenharmony_ci	int ret;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
59862306a36Sopenharmony_ci		ret = load_8051_config(ppd->dd, field_id, i, config_data);
59962306a36Sopenharmony_ci		if (ret != HCMD_SUCCESS) {
60062306a36Sopenharmony_ci			dd_dev_err(
60162306a36Sopenharmony_ci				ppd->dd,
60262306a36Sopenharmony_ci				"%s: %s for lane %u failed\n",
60362306a36Sopenharmony_ci				message, __func__, i);
60462306a36Sopenharmony_ci		}
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci}
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci/*
60962306a36Sopenharmony_ci * Return a special SerDes setting for low power AOC cables.  The power class
61062306a36Sopenharmony_ci * threshold and setting being used were all found by empirical testing.
61162306a36Sopenharmony_ci *
61262306a36Sopenharmony_ci * Summary of the logic:
61362306a36Sopenharmony_ci *
61462306a36Sopenharmony_ci * if (QSFP and QSFP_TYPE == AOC and QSFP_POWER_CLASS < 4)
61562306a36Sopenharmony_ci *     return 0xe
61662306a36Sopenharmony_ci * return 0; // leave at default
61762306a36Sopenharmony_ci */
61862306a36Sopenharmony_cistatic u8 aoc_low_power_setting(struct hfi1_pportdata *ppd)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
62162306a36Sopenharmony_ci	int power_class;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	/* QSFP only */
62462306a36Sopenharmony_ci	if (ppd->port_type != PORT_TYPE_QSFP)
62562306a36Sopenharmony_ci		return 0; /* leave at default */
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* active optical cables only */
62862306a36Sopenharmony_ci	switch ((cache[QSFP_MOD_TECH_OFFS] & 0xF0) >> 4) {
62962306a36Sopenharmony_ci	case 0x0 ... 0x9: fallthrough;
63062306a36Sopenharmony_ci	case 0xC: fallthrough;
63162306a36Sopenharmony_ci	case 0xE:
63262306a36Sopenharmony_ci		/* active AOC */
63362306a36Sopenharmony_ci		power_class = get_qsfp_power_class(cache[QSFP_MOD_PWR_OFFS]);
63462306a36Sopenharmony_ci		if (power_class < QSFP_POWER_CLASS_4)
63562306a36Sopenharmony_ci			return 0xe;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci	return 0; /* leave at default */
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic void apply_tunings(
64162306a36Sopenharmony_ci		struct hfi1_pportdata *ppd, u32 tx_preset_index,
64262306a36Sopenharmony_ci		u8 tuning_method, u32 total_atten, u8 limiting_active)
64362306a36Sopenharmony_ci{
64462306a36Sopenharmony_ci	int ret = 0;
64562306a36Sopenharmony_ci	u32 config_data = 0, tx_preset = 0;
64662306a36Sopenharmony_ci	u8 precur = 0, attn = 0, postcur = 0, external_device_config = 0;
64762306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	/* Pass tuning method to 8051 */
65062306a36Sopenharmony_ci	read_8051_config(ppd->dd, LINK_TUNING_PARAMETERS, GENERAL_CONFIG,
65162306a36Sopenharmony_ci			 &config_data);
65262306a36Sopenharmony_ci	config_data &= ~(0xff << TUNING_METHOD_SHIFT);
65362306a36Sopenharmony_ci	config_data |= ((u32)tuning_method << TUNING_METHOD_SHIFT);
65462306a36Sopenharmony_ci	ret = load_8051_config(ppd->dd, LINK_TUNING_PARAMETERS, GENERAL_CONFIG,
65562306a36Sopenharmony_ci			       config_data);
65662306a36Sopenharmony_ci	if (ret != HCMD_SUCCESS)
65762306a36Sopenharmony_ci		dd_dev_err(ppd->dd, "%s: Failed to set tuning method\n",
65862306a36Sopenharmony_ci			   __func__);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	/* Set same channel loss for both TX and RX */
66162306a36Sopenharmony_ci	config_data = 0 | (total_atten << 16) | (total_atten << 24);
66262306a36Sopenharmony_ci	apply_tx_lanes(ppd, CHANNEL_LOSS_SETTINGS, config_data,
66362306a36Sopenharmony_ci		       "Setting channel loss");
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/* Inform 8051 of cable capabilities */
66662306a36Sopenharmony_ci	if (ppd->qsfp_info.cache_valid) {
66762306a36Sopenharmony_ci		external_device_config =
66862306a36Sopenharmony_ci			((cache[QSFP_MOD_PWR_OFFS] & 0x4) << 3) |
66962306a36Sopenharmony_ci			((cache[QSFP_MOD_PWR_OFFS] & 0x8) << 2) |
67062306a36Sopenharmony_ci			((cache[QSFP_EQ_INFO_OFFS] & 0x2) << 1) |
67162306a36Sopenharmony_ci			(cache[QSFP_EQ_INFO_OFFS] & 0x4);
67262306a36Sopenharmony_ci		ret = read_8051_config(ppd->dd, DC_HOST_COMM_SETTINGS,
67362306a36Sopenharmony_ci				       GENERAL_CONFIG, &config_data);
67462306a36Sopenharmony_ci		/* Clear, then set the external device config field */
67562306a36Sopenharmony_ci		config_data &= ~(u32)0xFF;
67662306a36Sopenharmony_ci		config_data |= external_device_config;
67762306a36Sopenharmony_ci		ret = load_8051_config(ppd->dd, DC_HOST_COMM_SETTINGS,
67862306a36Sopenharmony_ci				       GENERAL_CONFIG, config_data);
67962306a36Sopenharmony_ci		if (ret != HCMD_SUCCESS)
68062306a36Sopenharmony_ci			dd_dev_err(ppd->dd,
68162306a36Sopenharmony_ci				   "%s: Failed set ext device config params\n",
68262306a36Sopenharmony_ci				   __func__);
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	if (tx_preset_index == OPA_INVALID_INDEX) {
68662306a36Sopenharmony_ci		if (ppd->port_type == PORT_TYPE_QSFP && limiting_active)
68762306a36Sopenharmony_ci			dd_dev_err(ppd->dd, "%s: Invalid Tx preset index\n",
68862306a36Sopenharmony_ci				   __func__);
68962306a36Sopenharmony_ci		return;
69062306a36Sopenharmony_ci	}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* Following for limiting active channels only */
69362306a36Sopenharmony_ci	get_platform_config_field(
69462306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_TX_PRESET_TABLE, tx_preset_index,
69562306a36Sopenharmony_ci		TX_PRESET_TABLE_PRECUR, &tx_preset, 4);
69662306a36Sopenharmony_ci	precur = tx_preset;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	get_platform_config_field(
69962306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_TX_PRESET_TABLE,
70062306a36Sopenharmony_ci		tx_preset_index, TX_PRESET_TABLE_ATTN, &tx_preset, 4);
70162306a36Sopenharmony_ci	attn = tx_preset;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	get_platform_config_field(
70462306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_TX_PRESET_TABLE,
70562306a36Sopenharmony_ci		tx_preset_index, TX_PRESET_TABLE_POSTCUR, &tx_preset, 4);
70662306a36Sopenharmony_ci	postcur = tx_preset;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/*
70962306a36Sopenharmony_ci	 * NOTES:
71062306a36Sopenharmony_ci	 * o The aoc_low_power_setting is applied to all lanes even
71162306a36Sopenharmony_ci	 *   though only lane 0's value is examined by the firmware.
71262306a36Sopenharmony_ci	 * o A lingering low power setting after a cable swap does
71362306a36Sopenharmony_ci	 *   not occur.  On cable unplug the 8051 is reset and
71462306a36Sopenharmony_ci	 *   restarted on cable insert.  This resets all settings to
71562306a36Sopenharmony_ci	 *   their default, erasing any previous low power setting.
71662306a36Sopenharmony_ci	 */
71762306a36Sopenharmony_ci	config_data = precur | (attn << 8) | (postcur << 16) |
71862306a36Sopenharmony_ci			(aoc_low_power_setting(ppd) << 24);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	apply_tx_lanes(ppd, TX_EQ_SETTINGS, config_data,
72162306a36Sopenharmony_ci		       "Applying TX settings");
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci/* Must be holding the QSFP i2c resource */
72562306a36Sopenharmony_cistatic int tune_active_qsfp(struct hfi1_pportdata *ppd, u32 *ptr_tx_preset,
72662306a36Sopenharmony_ci			    u32 *ptr_rx_preset, u32 *ptr_total_atten)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	int ret;
72962306a36Sopenharmony_ci	u16 lss = ppd->link_speed_supported, lse = ppd->link_speed_enabled;
73062306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	ppd->qsfp_info.limiting_active = 1;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	ret = set_qsfp_tx(ppd, 0);
73562306a36Sopenharmony_ci	if (ret)
73662306a36Sopenharmony_ci		return ret;
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	ret = qual_power(ppd);
73962306a36Sopenharmony_ci	if (ret)
74062306a36Sopenharmony_ci		return ret;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	ret = qual_bitrate(ppd);
74362306a36Sopenharmony_ci	if (ret)
74462306a36Sopenharmony_ci		return ret;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	/*
74762306a36Sopenharmony_ci	 * We'll change the QSFP memory contents from here on out, thus we set a
74862306a36Sopenharmony_ci	 * flag here to remind ourselves to reset the QSFP module. This prevents
74962306a36Sopenharmony_ci	 * reuse of stale settings established in our previous pass through.
75062306a36Sopenharmony_ci	 */
75162306a36Sopenharmony_ci	if (ppd->qsfp_info.reset_needed) {
75262306a36Sopenharmony_ci		ret = reset_qsfp(ppd);
75362306a36Sopenharmony_ci		if (ret)
75462306a36Sopenharmony_ci			return ret;
75562306a36Sopenharmony_ci		refresh_qsfp_cache(ppd, &ppd->qsfp_info);
75662306a36Sopenharmony_ci	} else {
75762306a36Sopenharmony_ci		ppd->qsfp_info.reset_needed = 1;
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	ret = set_qsfp_high_power(ppd);
76162306a36Sopenharmony_ci	if (ret)
76262306a36Sopenharmony_ci		return ret;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	if (cache[QSFP_EQ_INFO_OFFS] & 0x4) {
76562306a36Sopenharmony_ci		ret = get_platform_config_field(
76662306a36Sopenharmony_ci			ppd->dd,
76762306a36Sopenharmony_ci			PLATFORM_CONFIG_PORT_TABLE, 0,
76862306a36Sopenharmony_ci			PORT_TABLE_TX_PRESET_IDX_ACTIVE_EQ,
76962306a36Sopenharmony_ci			ptr_tx_preset, 4);
77062306a36Sopenharmony_ci		if (ret) {
77162306a36Sopenharmony_ci			*ptr_tx_preset = OPA_INVALID_INDEX;
77262306a36Sopenharmony_ci			return ret;
77362306a36Sopenharmony_ci		}
77462306a36Sopenharmony_ci	} else {
77562306a36Sopenharmony_ci		ret = get_platform_config_field(
77662306a36Sopenharmony_ci			ppd->dd,
77762306a36Sopenharmony_ci			PLATFORM_CONFIG_PORT_TABLE, 0,
77862306a36Sopenharmony_ci			PORT_TABLE_TX_PRESET_IDX_ACTIVE_NO_EQ,
77962306a36Sopenharmony_ci			ptr_tx_preset, 4);
78062306a36Sopenharmony_ci		if (ret) {
78162306a36Sopenharmony_ci			*ptr_tx_preset = OPA_INVALID_INDEX;
78262306a36Sopenharmony_ci			return ret;
78362306a36Sopenharmony_ci		}
78462306a36Sopenharmony_ci	}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	ret = get_platform_config_field(
78762306a36Sopenharmony_ci		ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
78862306a36Sopenharmony_ci		PORT_TABLE_RX_PRESET_IDX, ptr_rx_preset, 4);
78962306a36Sopenharmony_ci	if (ret) {
79062306a36Sopenharmony_ci		*ptr_rx_preset = OPA_INVALID_INDEX;
79162306a36Sopenharmony_ci		return ret;
79262306a36Sopenharmony_ci	}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if ((lss & OPA_LINK_SPEED_25G) && (lse & OPA_LINK_SPEED_25G))
79562306a36Sopenharmony_ci		get_platform_config_field(
79662306a36Sopenharmony_ci			ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
79762306a36Sopenharmony_ci			PORT_TABLE_LOCAL_ATTEN_25G, ptr_total_atten, 4);
79862306a36Sopenharmony_ci	else if ((lss & OPA_LINK_SPEED_12_5G) && (lse & OPA_LINK_SPEED_12_5G))
79962306a36Sopenharmony_ci		get_platform_config_field(
80062306a36Sopenharmony_ci			ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
80162306a36Sopenharmony_ci			PORT_TABLE_LOCAL_ATTEN_12G, ptr_total_atten, 4);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	apply_cdr_settings(ppd, *ptr_rx_preset, *ptr_tx_preset);
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	apply_eq_settings(ppd, *ptr_rx_preset, *ptr_tx_preset);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	apply_rx_amplitude_settings(ppd, *ptr_rx_preset, *ptr_tx_preset);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	ret = set_qsfp_tx(ppd, 1);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	return ret;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic int tune_qsfp(struct hfi1_pportdata *ppd,
81562306a36Sopenharmony_ci		     u32 *ptr_tx_preset, u32 *ptr_rx_preset,
81662306a36Sopenharmony_ci		     u8 *ptr_tuning_method, u32 *ptr_total_atten)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	u32 cable_atten = 0, remote_atten = 0, platform_atten = 0;
81962306a36Sopenharmony_ci	u16 lss = ppd->link_speed_supported, lse = ppd->link_speed_enabled;
82062306a36Sopenharmony_ci	int ret = 0;
82162306a36Sopenharmony_ci	u8 *cache = ppd->qsfp_info.cache;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	switch ((cache[QSFP_MOD_TECH_OFFS] & 0xF0) >> 4) {
82462306a36Sopenharmony_ci	case 0xA ... 0xB:
82562306a36Sopenharmony_ci		ret = get_platform_config_field(
82662306a36Sopenharmony_ci			ppd->dd,
82762306a36Sopenharmony_ci			PLATFORM_CONFIG_PORT_TABLE, 0,
82862306a36Sopenharmony_ci			PORT_TABLE_LOCAL_ATTEN_25G,
82962306a36Sopenharmony_ci			&platform_atten, 4);
83062306a36Sopenharmony_ci		if (ret)
83162306a36Sopenharmony_ci			return ret;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		if ((lss & OPA_LINK_SPEED_25G) && (lse & OPA_LINK_SPEED_25G))
83462306a36Sopenharmony_ci			cable_atten = cache[QSFP_CU_ATTEN_12G_OFFS];
83562306a36Sopenharmony_ci		else if ((lss & OPA_LINK_SPEED_12_5G) &&
83662306a36Sopenharmony_ci			 (lse & OPA_LINK_SPEED_12_5G))
83762306a36Sopenharmony_ci			cable_atten = cache[QSFP_CU_ATTEN_7G_OFFS];
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci		/* Fallback to configured attenuation if cable memory is bad */
84062306a36Sopenharmony_ci		if (cable_atten == 0 || cable_atten > 36) {
84162306a36Sopenharmony_ci			ret = get_platform_config_field(
84262306a36Sopenharmony_ci				ppd->dd,
84362306a36Sopenharmony_ci				PLATFORM_CONFIG_SYSTEM_TABLE, 0,
84462306a36Sopenharmony_ci				SYSTEM_TABLE_QSFP_ATTENUATION_DEFAULT_25G,
84562306a36Sopenharmony_ci				&cable_atten, 4);
84662306a36Sopenharmony_ci			if (ret)
84762306a36Sopenharmony_ci				return ret;
84862306a36Sopenharmony_ci		}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		ret = get_platform_config_field(
85162306a36Sopenharmony_ci			ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
85262306a36Sopenharmony_ci			PORT_TABLE_REMOTE_ATTEN_25G, &remote_atten, 4);
85362306a36Sopenharmony_ci		if (ret)
85462306a36Sopenharmony_ci			return ret;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		*ptr_total_atten = platform_atten + cable_atten + remote_atten;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci		*ptr_tuning_method = OPA_PASSIVE_TUNING;
85962306a36Sopenharmony_ci		break;
86062306a36Sopenharmony_ci	case 0x0 ... 0x9: fallthrough;
86162306a36Sopenharmony_ci	case 0xC: fallthrough;
86262306a36Sopenharmony_ci	case 0xE:
86362306a36Sopenharmony_ci		ret = tune_active_qsfp(ppd, ptr_tx_preset, ptr_rx_preset,
86462306a36Sopenharmony_ci				       ptr_total_atten);
86562306a36Sopenharmony_ci		if (ret)
86662306a36Sopenharmony_ci			return ret;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci		*ptr_tuning_method = OPA_ACTIVE_TUNING;
86962306a36Sopenharmony_ci		break;
87062306a36Sopenharmony_ci	case 0xD: fallthrough;
87162306a36Sopenharmony_ci	case 0xF:
87262306a36Sopenharmony_ci	default:
87362306a36Sopenharmony_ci		dd_dev_warn(ppd->dd, "%s: Unknown/unsupported cable\n",
87462306a36Sopenharmony_ci			    __func__);
87562306a36Sopenharmony_ci		break;
87662306a36Sopenharmony_ci	}
87762306a36Sopenharmony_ci	return ret;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci/*
88162306a36Sopenharmony_ci * This function communicates its success or failure via ppd->driver_link_ready
88262306a36Sopenharmony_ci * Thus, it depends on its association with start_link(...) which checks
88362306a36Sopenharmony_ci * driver_link_ready before proceeding with the link negotiation and
88462306a36Sopenharmony_ci * initialization process.
88562306a36Sopenharmony_ci */
88662306a36Sopenharmony_civoid tune_serdes(struct hfi1_pportdata *ppd)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	int ret = 0;
88962306a36Sopenharmony_ci	u32 total_atten = 0;
89062306a36Sopenharmony_ci	u32 remote_atten = 0, platform_atten = 0;
89162306a36Sopenharmony_ci	u32 rx_preset_index, tx_preset_index;
89262306a36Sopenharmony_ci	u8 tuning_method = 0, limiting_active = 0;
89362306a36Sopenharmony_ci	struct hfi1_devdata *dd = ppd->dd;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	rx_preset_index = OPA_INVALID_INDEX;
89662306a36Sopenharmony_ci	tx_preset_index = OPA_INVALID_INDEX;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	/* the link defaults to enabled */
89962306a36Sopenharmony_ci	ppd->link_enabled = 1;
90062306a36Sopenharmony_ci	/* the driver link ready state defaults to not ready */
90162306a36Sopenharmony_ci	ppd->driver_link_ready = 0;
90262306a36Sopenharmony_ci	ppd->offline_disabled_reason = HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/* Skip the tuning for testing (loopback != none) and simulations */
90562306a36Sopenharmony_ci	if (loopback != LOOPBACK_NONE ||
90662306a36Sopenharmony_ci	    ppd->dd->icode == ICODE_FUNCTIONAL_SIMULATOR) {
90762306a36Sopenharmony_ci		ppd->driver_link_ready = 1;
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci		if (qsfp_mod_present(ppd)) {
91062306a36Sopenharmony_ci			ret = acquire_chip_resource(ppd->dd,
91162306a36Sopenharmony_ci						    qsfp_resource(ppd->dd),
91262306a36Sopenharmony_ci						    QSFP_WAIT);
91362306a36Sopenharmony_ci			if (ret) {
91462306a36Sopenharmony_ci				dd_dev_err(ppd->dd, "%s: hfi%d: cannot lock i2c chain\n",
91562306a36Sopenharmony_ci					   __func__, (int)ppd->dd->hfi1_id);
91662306a36Sopenharmony_ci				goto bail;
91762306a36Sopenharmony_ci			}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci			refresh_qsfp_cache(ppd, &ppd->qsfp_info);
92062306a36Sopenharmony_ci			release_chip_resource(ppd->dd, qsfp_resource(ppd->dd));
92162306a36Sopenharmony_ci		}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci		return;
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	switch (ppd->port_type) {
92762306a36Sopenharmony_ci	case PORT_TYPE_DISCONNECTED:
92862306a36Sopenharmony_ci		ppd->offline_disabled_reason =
92962306a36Sopenharmony_ci			HFI1_ODR_MASK(OPA_LINKDOWN_REASON_DISCONNECTED);
93062306a36Sopenharmony_ci		dd_dev_warn(dd, "%s: Port disconnected, disabling port\n",
93162306a36Sopenharmony_ci			    __func__);
93262306a36Sopenharmony_ci		goto bail;
93362306a36Sopenharmony_ci	case PORT_TYPE_FIXED:
93462306a36Sopenharmony_ci		/* platform_atten, remote_atten pre-zeroed to catch error */
93562306a36Sopenharmony_ci		get_platform_config_field(
93662306a36Sopenharmony_ci			ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
93762306a36Sopenharmony_ci			PORT_TABLE_LOCAL_ATTEN_25G, &platform_atten, 4);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci		get_platform_config_field(
94062306a36Sopenharmony_ci			ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
94162306a36Sopenharmony_ci			PORT_TABLE_REMOTE_ATTEN_25G, &remote_atten, 4);
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci		total_atten = platform_atten + remote_atten;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci		tuning_method = OPA_PASSIVE_TUNING;
94662306a36Sopenharmony_ci		break;
94762306a36Sopenharmony_ci	case PORT_TYPE_VARIABLE:
94862306a36Sopenharmony_ci		if (qsfp_mod_present(ppd)) {
94962306a36Sopenharmony_ci			/*
95062306a36Sopenharmony_ci			 * platform_atten, remote_atten pre-zeroed to
95162306a36Sopenharmony_ci			 * catch error
95262306a36Sopenharmony_ci			 */
95362306a36Sopenharmony_ci			get_platform_config_field(
95462306a36Sopenharmony_ci				ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
95562306a36Sopenharmony_ci				PORT_TABLE_LOCAL_ATTEN_25G,
95662306a36Sopenharmony_ci				&platform_atten, 4);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci			get_platform_config_field(
95962306a36Sopenharmony_ci				ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0,
96062306a36Sopenharmony_ci				PORT_TABLE_REMOTE_ATTEN_25G,
96162306a36Sopenharmony_ci				&remote_atten, 4);
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci			total_atten = platform_atten + remote_atten;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci			tuning_method = OPA_PASSIVE_TUNING;
96662306a36Sopenharmony_ci		} else {
96762306a36Sopenharmony_ci			ppd->offline_disabled_reason =
96862306a36Sopenharmony_ci			     HFI1_ODR_MASK(OPA_LINKDOWN_REASON_CHASSIS_CONFIG);
96962306a36Sopenharmony_ci			goto bail;
97062306a36Sopenharmony_ci		}
97162306a36Sopenharmony_ci		break;
97262306a36Sopenharmony_ci	case PORT_TYPE_QSFP:
97362306a36Sopenharmony_ci		if (qsfp_mod_present(ppd)) {
97462306a36Sopenharmony_ci			ret = acquire_chip_resource(ppd->dd,
97562306a36Sopenharmony_ci						    qsfp_resource(ppd->dd),
97662306a36Sopenharmony_ci						    QSFP_WAIT);
97762306a36Sopenharmony_ci			if (ret) {
97862306a36Sopenharmony_ci				dd_dev_err(ppd->dd, "%s: hfi%d: cannot lock i2c chain\n",
97962306a36Sopenharmony_ci					   __func__, (int)ppd->dd->hfi1_id);
98062306a36Sopenharmony_ci				goto bail;
98162306a36Sopenharmony_ci			}
98262306a36Sopenharmony_ci			refresh_qsfp_cache(ppd, &ppd->qsfp_info);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci			if (ppd->qsfp_info.cache_valid) {
98562306a36Sopenharmony_ci				ret = tune_qsfp(ppd,
98662306a36Sopenharmony_ci						&tx_preset_index,
98762306a36Sopenharmony_ci						&rx_preset_index,
98862306a36Sopenharmony_ci						&tuning_method,
98962306a36Sopenharmony_ci						&total_atten);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci				/*
99262306a36Sopenharmony_ci				 * We may have modified the QSFP memory, so
99362306a36Sopenharmony_ci				 * update the cache to reflect the changes
99462306a36Sopenharmony_ci				 */
99562306a36Sopenharmony_ci				refresh_qsfp_cache(ppd, &ppd->qsfp_info);
99662306a36Sopenharmony_ci				limiting_active =
99762306a36Sopenharmony_ci						ppd->qsfp_info.limiting_active;
99862306a36Sopenharmony_ci			} else {
99962306a36Sopenharmony_ci				dd_dev_err(dd,
100062306a36Sopenharmony_ci					   "%s: Reading QSFP memory failed\n",
100162306a36Sopenharmony_ci					   __func__);
100262306a36Sopenharmony_ci				ret = -EINVAL; /* a fail indication */
100362306a36Sopenharmony_ci			}
100462306a36Sopenharmony_ci			release_chip_resource(ppd->dd, qsfp_resource(ppd->dd));
100562306a36Sopenharmony_ci			if (ret)
100662306a36Sopenharmony_ci				goto bail;
100762306a36Sopenharmony_ci		} else {
100862306a36Sopenharmony_ci			ppd->offline_disabled_reason =
100962306a36Sopenharmony_ci			   HFI1_ODR_MASK(
101062306a36Sopenharmony_ci				OPA_LINKDOWN_REASON_LOCAL_MEDIA_NOT_INSTALLED);
101162306a36Sopenharmony_ci			goto bail;
101262306a36Sopenharmony_ci		}
101362306a36Sopenharmony_ci		break;
101462306a36Sopenharmony_ci	default:
101562306a36Sopenharmony_ci		dd_dev_warn(ppd->dd, "%s: Unknown port type\n", __func__);
101662306a36Sopenharmony_ci		ppd->port_type = PORT_TYPE_UNKNOWN;
101762306a36Sopenharmony_ci		tuning_method = OPA_UNKNOWN_TUNING;
101862306a36Sopenharmony_ci		total_atten = 0;
101962306a36Sopenharmony_ci		limiting_active = 0;
102062306a36Sopenharmony_ci		tx_preset_index = OPA_INVALID_INDEX;
102162306a36Sopenharmony_ci		break;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	if (ppd->offline_disabled_reason ==
102562306a36Sopenharmony_ci			HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE))
102662306a36Sopenharmony_ci		apply_tunings(ppd, tx_preset_index, tuning_method,
102762306a36Sopenharmony_ci			      total_atten, limiting_active);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	if (!ret)
103062306a36Sopenharmony_ci		ppd->driver_link_ready = 1;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	return;
103362306a36Sopenharmony_cibail:
103462306a36Sopenharmony_ci	ppd->driver_link_ready = 0;
103562306a36Sopenharmony_ci}
1036