From 9be6a5d788b0f236e3b30827187e5db33231fa74 Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Mon, 2 Oct 2017 11:04:26 -0700 Subject: IB/hfi1: Prevent LNI out of sync by resetting host interface version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the link is disabled and re-enabled, the host version bit is not set again, so the firmware behaves as though it’s interacting with an old driver. This causes LNI to get out of sync. The host version bit needs to be set at load_8051_firmware() and _dc_start(). Currently, it's only set at load_8051_firmware(). Create a common function to set the bit with the intent to make the code more maintainable in the future, set the host version bit at _dc_start() and modify the 8051 command API to prevent a deadlock as _dc_start() is already holding the dc8051 lock. Fixes: 913cc67159bc ("IB/hfi1: Always perform offline transition") Reviewed-by: Dennis Dalessandro Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.h | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/infiniband/hw/hfi1/chip.h') diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h index b8345a60a0fb..579a6c70b93e 100644 --- a/drivers/infiniband/hw/hfi1/chip.h +++ b/drivers/infiniband/hw/hfi1/chip.h @@ -709,6 +709,7 @@ void read_misc_status(struct hfi1_devdata *dd, u8 *ver_major, u8 *ver_minor, u8 *ver_patch); int write_host_interface_version(struct hfi1_devdata *dd, u8 version); void read_guid(struct hfi1_devdata *dd); +int release_and_wait_ready_8051_firmware(struct hfi1_devdata *dd); int wait_fm_ready(struct hfi1_devdata *dd, u32 mstimeout); void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason, u8 neigh_reason, u8 rem_reason); -- cgit v1.2.3-59-g8ed1b From 242b494bf22be4056df1493664b00b5d0b238e53 Mon Sep 17 00:00:00 2001 From: Jan Sokolowski Date: Mon, 9 Oct 2017 13:08:28 -0700 Subject: IB/hfi1: Fix serdes loopback set-up Change serdes mode setting to use MISC_CONFIG_BITS in VERIFY_CAP_LOCAL_LINK_WIDTH register. This method of setting up serdes loopback is universally compatible across all firmware versions. Reviewed-by: Jakub Byczkowski Signed-off-by: Jan Sokolowski Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.c | 42 +++++++++++++-------------------------- drivers/infiniband/hw/hfi1/chip.h | 3 +++ 2 files changed, 17 insertions(+), 28 deletions(-) (limited to 'drivers/infiniband/hw/hfi1/chip.h') diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index b2ed4b9cda6e..160ada91e849 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -9156,25 +9156,6 @@ static int do_quick_linkup(struct hfi1_devdata *dd) return 0; /* success */ } -/* - * Set the SerDes to internal loopback mode. - * Returns 0 on success, -errno on error. - */ -static int set_serdes_loopback_mode(struct hfi1_devdata *dd) -{ - int ret; - - ret = set_physical_link_state(dd, PLS_INTERNAL_SERDES_LOOPBACK); - if (ret == HCMD_SUCCESS) - return 0; - dd_dev_err(dd, - "Set physical link state to SerDes Loopback failed with return %d\n", - ret); - if (ret >= 0) - ret = -EINVAL; - return ret; -} - /* * Do all special steps to set up loopback. */ @@ -9200,13 +9181,11 @@ static int init_loopback(struct hfi1_devdata *dd) return 0; } - /* handle serdes loopback */ - if (loopback == LOOPBACK_SERDES) { - /* internal serdes loopack needs quick linkup on RTL */ - if (dd->icode == ICODE_RTL_SILICON) - quick_linkup = 1; - return set_serdes_loopback_mode(dd); - } + /* + * SerDes loopback init sequence is handled in set_local_link_attributes + */ + if (loopback == LOOPBACK_SERDES) + return 0; /* LCB loopback - handled at poll time */ if (loopback == LOOPBACK_LCB) { @@ -9265,7 +9244,7 @@ static int set_local_link_attributes(struct hfi1_pportdata *ppd) u8 tx_polarity_inversion; u8 rx_polarity_inversion; int ret; - + u32 misc_bits = 0; /* reset our fabric serdes to clear any lingering problems */ fabric_serdes_reset(dd); @@ -9311,7 +9290,14 @@ static int set_local_link_attributes(struct hfi1_pportdata *ppd) if (ret != HCMD_SUCCESS) goto set_local_link_attributes_fail; - ret = write_vc_local_link_width(dd, 0, 0, + /* + * SerDes loopback init sequence requires + * setting bit 0 of MISC_CONFIG_BITS + */ + if (loopback == LOOPBACK_SERDES) + misc_bits |= 1 << LOOPBACK_SERDES_CONFIG_BIT_MASK_SHIFT; + + ret = write_vc_local_link_width(dd, misc_bits, 0, opa_to_vc_link_widths( ppd->link_width_enabled)); if (ret != HCMD_SUCCESS) diff --git a/drivers/infiniband/hw/hfi1/chip.h b/drivers/infiniband/hw/hfi1/chip.h index b8345a60a0fb..45b645e892c9 100644 --- a/drivers/infiniband/hw/hfi1/chip.h +++ b/drivers/infiniband/hw/hfi1/chip.h @@ -582,6 +582,9 @@ enum { #define LOOPBACK_LCB 2 #define LOOPBACK_CABLE 3 /* external cable */ +/* set up serdes bit in MISC_CONFIG_BITS */ +#define LOOPBACK_SERDES_CONFIG_BIT_MASK_SHIFT 0 + /* read and write hardware registers */ u64 read_csr(const struct hfi1_devdata *dd, u32 offset); void write_csr(const struct hfi1_devdata *dd, u32 offset, u64 value); -- cgit v1.2.3-59-g8ed1b