Denis Kirjanov 3e6c03
From 425afcb6aa408de4522f4be7530305490fca6c04 Mon Sep 17 00:00:00 2001
Denis Kirjanov 3e6c03
From: Vasundhara Volam <vasundhara-v.volam@broadcom.com>
Denis Kirjanov 3e6c03
Date: Mon, 26 Oct 2020 00:18:19 -0400
Denis Kirjanov 3e6c03
Subject: [PATCH 8/8] bnxt_en: Re-write PCI BARs after PCI fatal error.
Denis Kirjanov 3e6c03
Git-commit: f75d9a0aa96721d20011cd5f8c7a24eb32728589
Denis Kirjanov 3e6c03
Patch-mainline: v5.10-rc2
Denis Kirjanov 3e6c03
References: git-fixes
Denis Kirjanov 3e6c03
Denis Kirjanov 3e6c03
When a PCIe fatal error occurs, the internal latched BAR addresses
Denis Kirjanov 3e6c03
in the chip get reset even though the BAR register values in config
Denis Kirjanov 3e6c03
space are retained.
Denis Kirjanov 3e6c03
Denis Kirjanov 3e6c03
pci_restore_state() will not rewrite the BAR addresses if the
Denis Kirjanov 3e6c03
BAR address values are valid, causing the chip's internal BAR addresses
Denis Kirjanov 3e6c03
to stay invalid.  So we need to zero the BAR registers during PCIe fatal
Denis Kirjanov 3e6c03
error to force pci_restore_state() to restore the BAR addresses.  These
Denis Kirjanov 3e6c03
write cycles to the BAR registers will cause the proper BAR addresses to
Denis Kirjanov 3e6c03
latch internally.
Denis Kirjanov 3e6c03
Denis Kirjanov 3e6c03
Fixes: 6316ea6db93d ("bnxt_en: Enable AER support.")
Denis Kirjanov 3e6c03
Signed-off-by: Vasundhara Volam <vasundhara-v.volam@broadcom.com>
Denis Kirjanov 3e6c03
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Denis Kirjanov 3e6c03
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Denis Kirjanov 3e6c03
Signed-off-by: Denis Kirjanov <denis.kirjanov@suse.com>
Denis Kirjanov 3e6c03
---
Denis Kirjanov 3e6c03
 drivers/net/ethernet/broadcom/bnxt/bnxt.c | 19 ++++++++++++++++++-
Denis Kirjanov 3e6c03
 drivers/net/ethernet/broadcom/bnxt/bnxt.h |  1 +
Denis Kirjanov 3e6c03
 2 files changed, 19 insertions(+), 1 deletion(-)
Denis Kirjanov 3e6c03
Denis Kirjanov 3e6c03
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
Denis Kirjanov 3e6c03
index b1dbacc8d6d5..b1ba6df8911d 100644
Denis Kirjanov 3e6c03
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
Denis Kirjanov 3e6c03
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
Denis Kirjanov 3e6c03
@@ -10857,6 +10857,9 @@ static pci_ers_result_t bnxt_io_error_detected(struct pci_dev *pdev,
Denis Kirjanov 3e6c03
 		return PCI_ERS_RESULT_DISCONNECT;
Denis Kirjanov 3e6c03
 	}
Denis Kirjanov 3e6c03
 
Denis Kirjanov 3e6c03
+	if (state == pci_channel_io_frozen)
Denis Kirjanov 3e6c03
+		set_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state);
Denis Kirjanov 3e6c03
+
Denis Kirjanov 3e6c03
 	if (netif_running(netdev))
Denis Kirjanov 3e6c03
 		bnxt_close(netdev);
Denis Kirjanov 3e6c03
 
Denis Kirjanov 3e6c03
@@ -10884,7 +10887,7 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
Denis Kirjanov 3e6c03
 {
Denis Kirjanov 3e6c03
 	struct net_device *netdev = pci_get_drvdata(pdev);
Denis Kirjanov 3e6c03
 	struct bnxt *bp = netdev_priv(netdev);
Denis Kirjanov 3e6c03
-	int err = 0;
Denis Kirjanov 3e6c03
+	int err = 0, off;
Denis Kirjanov 3e6c03
 	pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT;
Denis Kirjanov 3e6c03
 
Denis Kirjanov 3e6c03
 	netdev_info(bp->dev, "PCI Slot Reset\n");
Denis Kirjanov 3e6c03
@@ -10896,6 +10899,20 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev)
Denis Kirjanov 3e6c03
 			"Cannot re-enable PCI device after reset.\n");
Denis Kirjanov 3e6c03
 	} else {
Denis Kirjanov 3e6c03
 		pci_set_master(pdev);
Denis Kirjanov 3e6c03
+		/* Upon fatal error, our device internal logic that latches to
Denis Kirjanov 3e6c03
+		 * BAR value is getting reset and will restore only upon
Denis Kirjanov 3e6c03
+		 * rewritting the BARs.
Denis Kirjanov 3e6c03
+		 *
Denis Kirjanov 3e6c03
+		 * As pci_restore_state() does not re-write the BARs if the
Denis Kirjanov 3e6c03
+		 * value is same as saved value earlier, driver needs to
Denis Kirjanov 3e6c03
+		 * write the BARs to 0 to force restore, in case of fatal error.
Denis Kirjanov 3e6c03
+		 */
Denis Kirjanov 3e6c03
+		if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN,
Denis Kirjanov 3e6c03
+				       &bp->state)) {
Denis Kirjanov 3e6c03
+			for (off = PCI_BASE_ADDRESS_0;
Denis Kirjanov 3e6c03
+			     off <= PCI_BASE_ADDRESS_5; off += 4)
Denis Kirjanov 3e6c03
+				pci_write_config_dword(bp->pdev, off, 0);
Denis Kirjanov 3e6c03
+		}
Denis Kirjanov 3e6c03
 		pci_restore_state(pdev);
Denis Kirjanov 3e6c03
 		pci_save_state(pdev);
Denis Kirjanov 3e6c03
 
Denis Kirjanov 3e6c03
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
Denis Kirjanov 3e6c03
index a2d616f1aaeb..11dc51e82fd6 100644
Denis Kirjanov 3e6c03
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
Denis Kirjanov 3e6c03
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
Denis Kirjanov 3e6c03
@@ -1462,6 +1462,7 @@ struct bnxt {
Denis Kirjanov 3e6c03
 #define BNXT_STATE_OPEN		0
Denis Kirjanov 3e6c03
 #define BNXT_STATE_IN_SP_TASK	1
Denis Kirjanov 3e6c03
 #define BNXT_STATE_READ_STATS	2
Denis Kirjanov 3e6c03
+#define BNXT_STATE_PCI_CHANNEL_IO_FROZEN	8
Denis Kirjanov 3e6c03
 
Denis Kirjanov 3e6c03
 	struct bnxt_irq	*irq_tbl;
Denis Kirjanov 3e6c03
 	int			total_irqs;
Denis Kirjanov 3e6c03
-- 
Denis Kirjanov 3e6c03
2.16.4
Denis Kirjanov 3e6c03