Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bnx2x: Prevent link flaps when booting from SAN.

It is possible that the driver is configured to operate with a certain
link configuration which differs from the link's configuration during
boot from SAN - this would cause the driver to flap the link.

Said flap may be missed by specific switches, causing dcbx convergence
to be too long and boot sequence to fail. Convergence is longer because
switch ignores new dcbx packets due to counters mismatch, as only host
side reset the counters due to the link flap.

This patch causes the driver to ignore user's initial configuration during
boot from SAN, and continues with the existing link configuration.

Signed-off-by: Barak Witkowski <barak@broadcom.com>
Signed-off-by: Yuval Mintz <yuvalmin@broadcom.com>
Signed-off-by: Eilon Greenstein <eilong@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Barak Witkowski and committed by
David S. Miller
c63da990 6ded7cd6

+34 -3
+1
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
··· 1186 1186 u8 slot; 1187 1187 u8 path; 1188 1188 struct list_head list; 1189 + u8 undi; 1189 1190 }; 1190 1191 1191 1192 struct bnx2x_sp_objs {
+1
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
··· 2396 2396 2397 2397 if (bp->port.pmf) 2398 2398 bnx2x_initial_phy_init(bp, load_mode); 2399 + bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_BOOT_FROM_SAN; 2399 2400 2400 2401 /* Start fast path */ 2401 2402
+6
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
··· 254 254 if (!(link_status & LINK_STATUS_LINK_UP)) 255 255 return LFA_LINK_DOWN; 256 256 257 + /* if loaded after BOOT from SAN, don't flap the link in any case and 258 + * rely on link set by preboot driver 259 + */ 260 + if (params->feature_config_flags & FEATURE_CONFIG_BOOT_FROM_SAN) 261 + return 0; 262 + 257 263 /* Verify that loopback mode is not set */ 258 264 if (params->loopback_mode) 259 265 return LFA_LOOPBACK_ENABLED;
+1
drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h
··· 267 267 #define FEATURE_CONFIG_BC_SUPPORTS_SFP_TX_DISABLED (1<<10) 268 268 #define FEATURE_CONFIG_DISABLE_REMOTE_FAULT_DET (1<<11) 269 269 #define FEATURE_CONFIG_MT_SUPPORT (1<<13) 270 + #define FEATURE_CONFIG_BOOT_FROM_SAN (1<<14) 270 271 271 272 /* Will be populated during common init */ 272 273 struct bnx2x_phy phy[MAX_PHYS];
+25 -3
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
··· 9515 9515 return 0; 9516 9516 } 9517 9517 9518 + static struct bnx2x_prev_path_list * 9519 + bnx2x_prev_path_get_entry(struct bnx2x *bp) 9520 + { 9521 + struct bnx2x_prev_path_list *tmp_list; 9522 + 9523 + list_for_each_entry(tmp_list, &bnx2x_prev_list, list) 9524 + if (PCI_SLOT(bp->pdev->devfn) == tmp_list->slot && 9525 + bp->pdev->bus->number == tmp_list->bus && 9526 + BP_PATH(bp) == tmp_list->path) 9527 + return tmp_list; 9528 + 9529 + return NULL; 9530 + } 9531 + 9518 9532 static bool bnx2x_prev_is_path_marked(struct bnx2x *bp) 9519 9533 { 9520 9534 struct bnx2x_prev_path_list *tmp_list; ··· 9553 9539 return rc; 9554 9540 } 9555 9541 9556 - static int bnx2x_prev_mark_path(struct bnx2x *bp) 9542 + static int bnx2x_prev_mark_path(struct bnx2x *bp, bool after_undi) 9557 9543 { 9558 9544 struct bnx2x_prev_path_list *tmp_list; 9559 9545 int rc; ··· 9567 9553 tmp_list->bus = bp->pdev->bus->number; 9568 9554 tmp_list->slot = PCI_SLOT(bp->pdev->devfn); 9569 9555 tmp_list->path = BP_PATH(bp); 9556 + tmp_list->undi = after_undi ? (1 << BP_PORT(bp)) : 0; 9570 9557 9571 9558 rc = down_interruptible(&bnx2x_prev_sem); 9572 9559 if (rc) { ··· 9664 9649 static int bnx2x_prev_unload_common(struct bnx2x *bp) 9665 9650 { 9666 9651 u32 reset_reg, tmp_reg = 0, rc; 9652 + bool prev_undi = false; 9667 9653 /* It is possible a previous function received 'common' answer, 9668 9654 * but hasn't loaded yet, therefore creating a scenario of 9669 9655 * multiple functions receiving 'common' on the same path. ··· 9679 9663 /* Reset should be performed after BRB is emptied */ 9680 9664 if (reset_reg & MISC_REGISTERS_RESET_REG_1_RST_BRB1) { 9681 9665 u32 timer_count = 1000; 9682 - bool prev_undi = false; 9683 9666 9684 9667 /* Close the MAC Rx to prevent BRB from filling up */ 9685 9668 bnx2x_prev_unload_close_mac(bp); ··· 9728 9713 /* No packets are in the pipeline, path is ready for reset */ 9729 9714 bnx2x_reset_common(bp); 9730 9715 9731 - rc = bnx2x_prev_mark_path(bp); 9716 + rc = bnx2x_prev_mark_path(bp, prev_undi); 9732 9717 if (rc) { 9733 9718 bnx2x_prev_mcp_done(bp); 9734 9719 return rc; ··· 9760 9745 { 9761 9746 int time_counter = 10; 9762 9747 u32 rc, fw, hw_lock_reg, hw_lock_val; 9748 + struct bnx2x_prev_path_list *prev_list; 9763 9749 BNX2X_DEV_INFO("Entering Previous Unload Flow\n"); 9764 9750 9765 9751 /* clear hw from errors which may have resulted from an interrupted ··· 9818 9802 BNX2X_ERR("Failed unloading previous driver, aborting\n"); 9819 9803 rc = -EBUSY; 9820 9804 } 9805 + 9806 + /* Mark function if its port was used to boot from SAN */ 9807 + prev_list = bnx2x_prev_path_get_entry(bp); 9808 + if (prev_list && (prev_list->undi & (1 << BP_PORT(bp)))) 9809 + bp->link_params.feature_config_flags |= 9810 + FEATURE_CONFIG_BOOT_FROM_SAN; 9821 9811 9822 9812 BNX2X_DEV_INFO("Finished Previous Unload Flow [%d]\n", rc); 9823 9813