// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
* Copyright(c) 2015, 2016 Intel Corporation.
*/
#include <linux/firmware.h>
#include "hfi.h"
#include "efivar.h"
#include "eprom.h"
#define DEFAULT_PLATFORM_CONFIG_NAME "hfi1_platform.dat"
static int validate_scratch_checksum(struct hfi1_devdata *dd)
{
u64 checksum = 0, temp_scratch = 0;
int i, j, version;
temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH);
version = (temp_scratch & BITMAP_VERSION_SMASK) >> BITMAP_VERSION_SHIFT;
/* Prevent power on default of all zeroes from passing checksum */
if (!version) {
dd_dev_err(dd, "%s: Config bitmap uninitialized\n", __func__);
dd_dev_err(dd,
"%s: Please update your BIOS to support active channels\n",
__func__);
return 0;
}
/*
* ASIC scratch 0 only contains the checksum and bitmap version as
* fields of interest, both of which are handled separately from the
* loop below, so skip it
*/
checksum += version;
for (i = 1; i < ASIC_NUM_SCRATCH; i++) {
temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH + (8 * i));
for (j = sizeof(u64); j != 0; j -= 2) {
checksum += (temp_scratch & 0xFFFF);
temp_scratch >>= 16;
}
}
while (checksum >> 16)
checksum = (checksum & CHECKSUM_MASK) + (checksum >> 16);
temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH);
temp_scratch &= CHECKSUM_SMASK;
temp_scratch >>= CHECKSUM_SHIFT;
if (checksum + temp_scratch == 0xFFFF)
return 1;
dd_dev_err(dd, "%s: Configuration bitmap corrupted\n", __func__);
return 0;
}
static void save_platform_config_fields(struct hfi1_devdata *dd)
{
struct hfi1_pportdata *ppd = dd->pport;
u64 temp_scratch = 0, temp_dest = 0;
temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH_1);
temp_dest = temp_scratch &
(dd->hfi1_id ? PORT1_PORT_TYPE_SMASK :
PORT0_PORT_TYPE_SMASK);
ppd->port_type = temp_dest >>
(dd->hfi1_id ? PORT1_PORT_TYPE_SHIFT :
PORT0_PORT_TYPE_SHIFT);
temp_dest = temp_scratch &
(dd->hfi1_id ? PORT1_LOCAL_ATTEN_SMASK :
PORT0_LOCAL_ATTEN_SMASK);
ppd->local_atten = temp_dest >>
(dd->hfi1_id ? PORT1_LOCAL_ATTEN_SHIFT :
PORT0_LOCAL_ATTEN_SHIFT);
temp_dest = temp_scratch &
(dd->hfi1_id ? PORT1_REMOTE_ATTEN_SMASK :
PORT0_REMOTE_ATTEN_SMASK);
ppd->remote_atten = temp_dest >>
(dd->hfi1_id ? PORT1_REMOTE_ATTEN_SHIFT :
PORT0_REMOTE_ATTEN_SHIFT);
temp_dest = temp_scratch &
(dd->hfi1_id ? PORT1_DEFAULT_ATTEN_SMASK :
PORT0_DEFAULT_ATTEN_SMASK);
ppd->default_atten = temp_dest >>
(dd->hfi1_id ? PORT1_DEFAULT_ATTEN_SHIFT :
PORT0_DEFAULT_ATTEN_SHIFT);
temp_scratch = read_csr(dd, dd->hfi1_id ? ASIC_CFG_SCRATCH_3 :
ASIC_CFG_SCRATCH_2);
ppd->tx_preset_eq = (temp_scratch & TX_EQ_SMASK) >> TX_EQ_SHIFT;
ppd->tx_preset_noeq = (temp_scratch & TX_NO_EQ_SMASK) >> TX_NO_EQ_SHIFT;
ppd->rx_preset = (temp_scratch & RX_SMASK) >> RX_SHIFT;
ppd->max_power_class = (temp_scratch & QSFP_MAX_POWER_SMASK) >>
QSFP_MAX_POWER_SHIFT;
ppd->config_from_scratch = true;
}
void get_platform_config(struct hfi1_devdata *dd)
{
int ret = 0;
u8 *temp_platform_config = NULL;
u32 esize;
const struct firmware *platform_config_file = NULL;
if (is_integrated(dd)) {
if (validate_scratch_checksum(dd)) {
save_platform_config_fields(dd