&dd->pcidev->dev);
if (err) {
platform_config = NULL;
- fw_state = FW_ERR;
- fw_err = -ENOENT;
goto done;
}
dd->platform_config.data = platform_config->data;
return obtain_firmware(dd);
}
+/*
+ * This function is a helper function for parse_platform_config(...) and
+ * does not check for validity of the platform configuration cache
+ * (because we know it is invalid as we are building up the cache).
+ * As such, this should not be called from anywhere other than
+ * parse_platform_config
+ */
+static int check_meta_version(struct hfi1_devdata *dd, u32 *system_table)
+{
+ u32 meta_ver, meta_ver_meta, ver_start, ver_len, mask;
+ struct platform_config_cache *pcfgcache = &dd->pcfg_cache;
+
+ if (!system_table)
+ return -EINVAL;
+
+ meta_ver_meta =
+ *(pcfgcache->config_tables[PLATFORM_CONFIG_SYSTEM_TABLE].table_metadata
+ + SYSTEM_TABLE_META_VERSION);
+
+ mask = ((1 << METADATA_TABLE_FIELD_START_LEN_BITS) - 1);
+ ver_start = meta_ver_meta & mask;
+
+ meta_ver_meta >>= METADATA_TABLE_FIELD_LEN_SHIFT;
+
+ mask = ((1 << METADATA_TABLE_FIELD_LEN_LEN_BITS) - 1);
+ ver_len = meta_ver_meta & mask;
+
+ ver_start /= 8;
+ meta_ver = *((u8 *)system_table + ver_start) & ((1 << ver_len) - 1);
+
+ if (meta_ver < 5) {
+ dd_dev_info(
+ dd, "%s:Please update platform config\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
int parse_platform_config(struct hfi1_devdata *dd)
{
struct platform_config_cache *pcfgcache = &dd->pcfg_cache;
u32 *ptr = NULL;
u32 header1 = 0, header2 = 0, magic_num = 0, crc = 0, file_length = 0;
u32 record_idx = 0, table_type = 0, table_length_dwords = 0;
+ int ret = -EINVAL; /* assume failure */
if (!dd->platform_config.data) {
dd_dev_info(dd, "%s: Missing config file\n", __func__);
__func__);
goto bail;
} else if (file_length < dd->platform_config.size) {
- dd_dev_info(dd, "%s:File claims to be smaller than read size\n",
+ dd_dev_info(dd,
+ "%s:File claims to be smaller than read size, continuing\n",
__func__);
}
/* exactly equal, perfection */
case PLATFORM_CONFIG_SYSTEM_TABLE:
pcfgcache->config_tables[table_type].num_table =
1;
+ ret = check_meta_version(dd, ptr);
+ if (ret)
+ goto bail;
break;
case PLATFORM_CONFIG_PORT_TABLE:
pcfgcache->config_tables[table_type].num_table =
return 0;
bail:
memset(pcfgcache, 0, sizeof(struct platform_config_cache));
- return -EINVAL;
+ return ret;
}
static int get_platform_fw_field_metadata(struct hfi1_devdata *dd, int table,
#define OPA_INVALID_INDEX 0xFFF
-static void apply_tx_lanes(struct hfi1_pportdata *ppd, u32 config_data,
- const char *message)
+static void apply_tx_lanes(struct hfi1_pportdata *ppd, u8 field_id,
+ u32 config_data, const char *message)
{
u8 i;
int ret = HCMD_SUCCESS;
for (i = 0; i < 4; i++) {
- ret = load_8051_config(ppd->dd, 0, i, config_data);
+ ret = load_8051_config(ppd->dd, field_id, i, config_data);
if (ret != HCMD_SUCCESS) {
dd_dev_err(
ppd->dd,
u8 precur = 0, attn = 0, postcur = 0, external_device_config = 0;
u8 *cache = ppd->qsfp_info.cache;
+ /* Enable external device config if channel is limiting active */
read_8051_config(ppd->dd, LINK_OPTIMIZATION_SETTINGS,
GENERAL_CONFIG, &config_data);
config_data |= limiting_active;
__func__);
config_data = 0; /* re-init */
+ /* Pass tuning method to 8051 */
read_8051_config(ppd->dd, LINK_TUNING_PARAMETERS, GENERAL_CONFIG,
&config_data);
config_data |= tuning_method;
dd_dev_err(ppd->dd, "%s: Failed to set tuning method\n",
__func__);
- external_device_config =
- ((cache[QSFP_MOD_PWR_OFFS] & 0x4) << 3) |
- ((cache[QSFP_MOD_PWR_OFFS] & 0x8) << 2) |
- ((cache[QSFP_EQ_INFO_OFFS] & 0x2) << 1) |
- (cache[QSFP_EQ_INFO_OFFS] & 0x4);
-
- config_data = 0; /* re-init */
- read_8051_config(ppd->dd, DC_HOST_COMM_SETTINGS, GENERAL_CONFIG,
- &config_data);
- config_data |= (external_device_config << 24);
- ret = load_8051_config(ppd->dd, DC_HOST_COMM_SETTINGS, GENERAL_CONFIG,
- config_data);
- if (ret != HCMD_SUCCESS)
- dd_dev_err(
- ppd->dd,
- "%s: Failed to set external device config parameters\n",
- __func__);
-
- config_data = 0; /* re-init */
- read_8051_config(ppd->dd, TX_SETTINGS, GENERAL_CONFIG, &config_data);
- if ((ppd->link_speed_supported & OPA_LINK_SPEED_25G) &&
- (ppd->link_speed_enabled & OPA_LINK_SPEED_25G))
- config_data |= 0x02;
- if ((ppd->link_speed_supported & OPA_LINK_SPEED_12_5G) &&
- (ppd->link_speed_enabled & OPA_LINK_SPEED_12_5G))
- config_data |= 0x01;
- ret = load_8051_config(ppd->dd, TX_SETTINGS, GENERAL_CONFIG,
- config_data);
- if (ret != HCMD_SUCCESS)
- dd_dev_err(
- ppd->dd,
- "%s: Failed to set external device config parameters\n",
- __func__);
-
- config_data = (total_atten << 8) | (total_atten);
-
- apply_tx_lanes(ppd, config_data, "Setting channel loss");
+ /* Set same channel loss for both TX and RX */
+ config_data = 0 | (total_atten << 16) | (total_atten << 24);
+ apply_tx_lanes(ppd, CHANNEL_LOSS_SETTINGS, config_data,
+ "Setting channel loss");
+
+ /* Inform 8051 of cable capabilities */
+ if (ppd->qsfp_info.cache_valid) {
+ external_device_config =
+ ((cache[QSFP_MOD_PWR_OFFS] & 0x4) << 3) |
+ ((cache[QSFP_MOD_PWR_OFFS] & 0x8) << 2) |
+ ((cache[QSFP_EQ_INFO_OFFS] & 0x2) << 1) |
+ (cache[QSFP_EQ_INFO_OFFS] & 0x4);
+ ret = read_8051_config(ppd->dd, DC_HOST_COMM_SETTINGS,
+ GENERAL_CONFIG, &config_data);
+ /* Clear, then set the external device config field */
+ config_data &= ~(0xFF << 24);
+ config_data |= (external_device_config << 24);
+ ret = load_8051_config(ppd->dd, DC_HOST_COMM_SETTINGS,
+ GENERAL_CONFIG, config_data);
+ if (ret != HCMD_SUCCESS)
+ dd_dev_info(ppd->dd,
+ "%s: Failed set ext device config params\n",
+ __func__);
+ }
- if (tx_preset_index == OPA_INVALID_INDEX)
+ if (tx_preset_index == OPA_INVALID_INDEX) {
+ if (ppd->port_type == PORT_TYPE_QSFP && limiting_active)
+ dd_dev_info(ppd->dd, "%s: Invalid Tx preset index\n",
+ __func__);
return;
+ }
+ /* Following for limiting active channels only */
get_platform_config_field(
ppd->dd, PLATFORM_CONFIG_TX_PRESET_TABLE, tx_preset_index,
TX_PRESET_TABLE_PRECUR, &tx_preset, 4);
config_data = precur | (attn << 8) | (postcur << 16);
- apply_tx_lanes(ppd, config_data, "Applying TX settings");
+ apply_tx_lanes(ppd, TX_EQ_SETTINGS, config_data,
+ "Applying TX settings");
}
static int tune_active_qsfp(struct hfi1_pportdata *ppd, u32 *ptr_tx_preset,
u32 total_atten = 0;
u32 remote_atten = 0, platform_atten = 0;
u32 rx_preset_index, tx_preset_index;
- u8 tuning_method = 0;
+ u8 tuning_method = 0, limiting_active = 0;
struct hfi1_devdata *dd = ppd->dd;
rx_preset_index = OPA_INVALID_INDEX;
PORT_TABLE_PORT_TYPE, &ppd->port_type,
4);
if (ret)
- goto bail;
+ ppd->port_type = PORT_TYPE_UNKNOWN;
switch (ppd->port_type) {
case PORT_TYPE_DISCONNECTED:
refresh_qsfp_cache(ppd, &ppd->qsfp_info);
if (ret)
goto bail;
+
+ limiting_active =
+ ppd->qsfp_info.limiting_active;
} else {
dd_dev_err(dd,
"%s: Reading QSFP memory failed\n",
break;
default:
dd_dev_info(ppd->dd, "%s: Unknown port type\n", __func__);
- goto bail;
+ ppd->port_type = PORT_TYPE_UNKNOWN;
+ tuning_method = OPA_UNKNOWN_TUNING;
+ total_atten = 0;
+ limiting_active = 0;
+ tx_preset_index = OPA_INVALID_INDEX;
+ break;
}
+
if (ppd->offline_disabled_reason ==
HFI1_ODR_MASK(OPA_LINKDOWN_REASON_NONE))
apply_tunings(ppd, tx_preset_index, tuning_method,
- total_atten,
- ppd->qsfp_info.limiting_active);
+ total_atten, limiting_active);
if (!ret)
ppd->driver_link_ready = 1;