[3/9] net/ngbe: fix Tx pending

Message ID 20220208101129.69173-4-jiawenwu@trustnetic.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series Wangxun fixes and supports |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Jiawen Wu Feb. 8, 2022, 10:11 a.m. UTC
  Add commands requesting firmware to enable or disable PCIe bus master.
Disable PCIe master access to clear BME when stop hardware, and verify
there are no pending requests.

Fixes: 78710873c2f3 ("net/ngbe: add HW initialization")
Cc: stable@dpdk.org

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
 drivers/net/ngbe/base/ngbe_hw.c   | 76 +++++++++++++++++++++++++++----
 drivers/net/ngbe/base/ngbe_hw.h   |  1 +
 drivers/net/ngbe/base/ngbe_mng.c  | 57 +++++++++++++++++++++++
 drivers/net/ngbe/base/ngbe_mng.h  | 21 +++++++++
 drivers/net/ngbe/base/ngbe_regs.h |  3 ++
 drivers/net/ngbe/base/ngbe_type.h |  3 ++
 drivers/net/ngbe/ngbe_ethdev.c    |  7 ++-
 7 files changed, 158 insertions(+), 10 deletions(-)
  

Comments

Ferruh Yigit Feb. 8, 2022, 5:38 p.m. UTC | #1
On 2/8/2022 10:11 AM, Jiawen Wu wrote:
> Add commands requesting firmware to enable or disable PCIe bus master.
> Disable PCIe master access to clear BME when stop hardware, and verify
> there are no pending requests.
> 

Hi Jiawen,

Can you please describe more what is fixed in this patch?

As far as I understand PCI-e bus hang during HW stop is fixed, by disabling
pci-e bus master.
But patch title mentions from Tx, can you please clarify the relation?

Thanks,
ferruh

> Fixes: 78710873c2f3 ("net/ngbe: add HW initialization")
> Cc: stable@dpdk.org
> 
> Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>


<...>
  

Patch

diff --git a/drivers/net/ngbe/base/ngbe_hw.c b/drivers/net/ngbe/base/ngbe_hw.c
index 0b22ea0fb3..782fd71d29 100644
--- a/drivers/net/ngbe/base/ngbe_hw.c
+++ b/drivers/net/ngbe/base/ngbe_hw.c
@@ -350,8 +350,8 @@  void ngbe_set_lan_id_multi_port(struct ngbe_hw *hw)
  **/
 s32 ngbe_stop_hw(struct ngbe_hw *hw)
 {
-	u32 reg_val;
 	u16 i;
+	s32 status = 0;
 
 	DEBUGFUNC("ngbe_stop_hw");
 
@@ -372,16 +372,27 @@  s32 ngbe_stop_hw(struct ngbe_hw *hw)
 	wr32(hw, NGBE_ICRMISC, NGBE_ICRMISC_MASK);
 	wr32(hw, NGBE_ICR(0), NGBE_ICR_MASK);
 
-	/* Disable the transmit unit.  Each queue must be disabled. */
-	for (i = 0; i < hw->mac.max_tx_queues; i++)
-		wr32(hw, NGBE_TXCFG(i), NGBE_TXCFG_FLUSH);
+	wr32(hw, NGBE_BMECTL, 0x3);
 
 	/* Disable the receive unit by stopping each queue */
-	for (i = 0; i < hw->mac.max_rx_queues; i++) {
-		reg_val = rd32(hw, NGBE_RXCFG(i));
-		reg_val &= ~NGBE_RXCFG_ENA;
-		wr32(hw, NGBE_RXCFG(i), reg_val);
-	}
+	for (i = 0; i < hw->mac.max_rx_queues; i++)
+		wr32(hw, NGBE_RXCFG(i), 0);
+
+	/* flush all queues disables */
+	ngbe_flush(hw);
+	msec_delay(2);
+
+	/*
+	 * Prevent the PCI-E bus from hanging by disabling PCI-E master
+	 * access and verify no pending requests
+	 */
+	status = ngbe_set_pcie_master(hw, false);
+	if (status)
+		return status;
+
+	/* Disable the transmit unit.  Each queue must be disabled. */
+	for (i = 0; i < hw->mac.max_tx_queues; i++)
+		wr32(hw, NGBE_TXCFG(i), 0);
 
 	/* flush all queues disables */
 	ngbe_flush(hw);
@@ -1076,6 +1087,53 @@  void ngbe_fc_autoneg(struct ngbe_hw *hw)
 	}
 }
 
+/**
+ *  ngbe_set_pcie_master - Disable or Enable PCI-express master access
+ *  @hw: pointer to hardware structure
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests. NGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable
+ *  bit hasn't caused the master requests to be disabled, else 0
+ *  is returned signifying master requests disabled.
+ **/
+s32 ngbe_set_pcie_master(struct ngbe_hw *hw, bool enable)
+{
+	s32 status = 0;
+	u16 addr = 0x04;
+	u32 data, i;
+
+	DEBUGFUNC("ngbe_set_pcie_master");
+
+	ngbe_hic_pcie_read(hw, addr, &data, 4);
+	if (enable)
+		data |= 0x04;
+	else
+		data &= ~0x04;
+
+	ngbe_hic_pcie_write(hw, addr, &data, 4);
+
+	if (enable)
+		goto out;
+
+	/* Exit if master requests are blocked */
+	if (!(rd32(hw, NGBE_BMEPEND)) ||
+	    NGBE_REMOVED(hw->hw_addr))
+		goto out;
+
+	/* Poll for master request bit to clear */
+	for (i = 0; i < NGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+		usec_delay(100);
+		if (!(rd32(hw, NGBE_BMEPEND)))
+			goto out;
+	}
+
+	DEBUGOUT("PCIe transaction pending bit also did not clear.\n");
+	status = NGBE_ERR_MASTER_REQUESTS_PENDING;
+
+out:
+	return status;
+}
+
 /**
  *  ngbe_acquire_swfw_sync - Acquire SWFW semaphore
  *  @hw: pointer to hardware structure
diff --git a/drivers/net/ngbe/base/ngbe_hw.h b/drivers/net/ngbe/base/ngbe_hw.h
index b32cf87ff4..7e0e23b195 100644
--- a/drivers/net/ngbe/base/ngbe_hw.h
+++ b/drivers/net/ngbe/base/ngbe_hw.h
@@ -54,6 +54,7 @@  void ngbe_fc_autoneg(struct ngbe_hw *hw);
 s32 ngbe_validate_mac_addr(u8 *mac_addr);
 s32 ngbe_acquire_swfw_sync(struct ngbe_hw *hw, u32 mask);
 void ngbe_release_swfw_sync(struct ngbe_hw *hw, u32 mask);
+s32 ngbe_set_pcie_master(struct ngbe_hw *hw, bool enable);
 
 s32 ngbe_set_vmdq(struct ngbe_hw *hw, u32 rar, u32 vmdq);
 s32 ngbe_clear_vmdq(struct ngbe_hw *hw, u32 rar, u32 vmdq);
diff --git a/drivers/net/ngbe/base/ngbe_mng.c b/drivers/net/ngbe/base/ngbe_mng.c
index a3dd8093ce..68e06e2c24 100644
--- a/drivers/net/ngbe/base/ngbe_mng.c
+++ b/drivers/net/ngbe/base/ngbe_mng.c
@@ -243,6 +243,63 @@  s32 ngbe_hic_sr_write(struct ngbe_hw *hw, u32 addr, u8 *buf, int len)
 	return err;
 }
 
+s32 ngbe_hic_pcie_read(struct ngbe_hw *hw, u16 addr, u32 *buf, int len)
+{
+	struct ngbe_hic_read_pcie command;
+	u32 value = 0;
+	int err, i = 0;
+
+	if (len > NGBE_PMMBX_DATA_SIZE)
+		return NGBE_ERR_HOST_INTERFACE_COMMAND;
+
+	memset(&command, 0, sizeof(command));
+	command.hdr.cmd = FW_PCIE_READ_CMD;
+	command.hdr.buf_len = sizeof(command) - sizeof(command.hdr);
+	command.hdr.checksum = FW_DEFAULT_CHECKSUM;
+	command.lan_id = hw->bus.lan_id;
+	command.addr = addr;
+
+	err = ngbe_host_interface_command(hw, (u32 *)&command,
+			sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false);
+	if (err)
+		return err;
+
+	while (i < (len >> 2)) {
+		value = rd32a(hw, NGBE_MNGMBX, FW_PCIE_BUSMASTER_OFFSET + i);
+		((u32 *)buf)[i] = value;
+		i++;
+	}
+
+	return 0;
+}
+
+s32 ngbe_hic_pcie_write(struct ngbe_hw *hw, u16 addr, u32 *buf, int len)
+{
+	struct ngbe_hic_write_pcie command;
+	u32 value = 0;
+	int err, i = 0;
+
+	while (i < (len >> 2)) {
+		value = ((u32 *)buf)[i];
+		i++;
+	}
+
+	memset(&command, 0, sizeof(command));
+	command.hdr.cmd = FW_PCIE_WRITE_CMD;
+	command.hdr.buf_len = sizeof(command) - sizeof(command.hdr);
+	command.hdr.checksum = FW_DEFAULT_CHECKSUM;
+	command.lan_id = hw->bus.lan_id;
+	command.addr = addr;
+	command.data = value;
+
+	err = ngbe_host_interface_command(hw, (u32 *)&command,
+			sizeof(command), NGBE_HI_COMMAND_TIMEOUT, false);
+	if (err)
+		return err;
+
+	return 0;
+}
+
 s32 ngbe_hic_check_cap(struct ngbe_hw *hw)
 {
 	struct ngbe_hic_read_shadow_ram command;
diff --git a/drivers/net/ngbe/base/ngbe_mng.h b/drivers/net/ngbe/base/ngbe_mng.h
index e3d0309cbc..321338a051 100644
--- a/drivers/net/ngbe/base/ngbe_mng.h
+++ b/drivers/net/ngbe/base/ngbe_mng.h
@@ -20,6 +20,9 @@ 
 #define FW_READ_SHADOW_RAM_LEN          0x6
 #define FW_WRITE_SHADOW_RAM_CMD         0x33
 #define FW_WRITE_SHADOW_RAM_LEN         0xA /* 8 plus 1 WORD to write */
+#define FW_PCIE_READ_CMD		0xEC
+#define FW_PCIE_WRITE_CMD		0xED
+#define FW_PCIE_BUSMASTER_OFFSET        2
 #define FW_DEFAULT_CHECKSUM             0xFF /* checksum always 0xFF */
 #define FW_NVM_DATA_OFFSET              3
 #define FW_EEPROM_CHECK_STATUS		0xE9
@@ -76,8 +79,26 @@  struct ngbe_hic_write_shadow_ram {
 	u16 pad3;
 };
 
+struct ngbe_hic_read_pcie {
+	struct ngbe_hic_hdr hdr;
+	u8 lan_id;
+	u8 rsvd;
+	u16 addr;
+	u32 data;
+};
+
+struct ngbe_hic_write_pcie {
+	struct ngbe_hic_hdr hdr;
+	u8 lan_id;
+	u8 rsvd;
+	u16 addr;
+	u32 data;
+};
+
 s32 ngbe_hic_sr_read(struct ngbe_hw *hw, u32 addr, u8 *buf, int len);
 s32 ngbe_hic_sr_write(struct ngbe_hw *hw, u32 addr, u8 *buf, int len);
+s32 ngbe_hic_pcie_read(struct ngbe_hw *hw, u16 addr, u32 *buf, int len);
+s32 ngbe_hic_pcie_write(struct ngbe_hw *hw, u16 addr, u32 *buf, int len);
 
 s32 ngbe_hic_check_cap(struct ngbe_hw *hw);
 #endif /* _NGBE_MNG_H_ */
diff --git a/drivers/net/ngbe/base/ngbe_regs.h b/drivers/net/ngbe/base/ngbe_regs.h
index 872b008c46..e84bfdf88a 100644
--- a/drivers/net/ngbe/base/ngbe_regs.h
+++ b/drivers/net/ngbe/base/ngbe_regs.h
@@ -866,6 +866,9 @@  enum ngbe_5tuple_protocol {
  * PF(Physical Function) Registers
  ******************************************************************************/
 /* Interrupt */
+#define NGBE_BMECTL		0x012020
+#define   NGBE_BMECTL_VFDRP	MS(1, 0x1)
+#define   NGBE_BMECTL_PFDRP	MS(0, 0x1)
 #define NGBE_ICRMISC		0x000100
 #define   NGBE_ICRMISC_MASK	MS(8, 0xFFFFFF)
 #define   NGBE_ICRMISC_RST	MS(10, 0x1) /* device reset event */
diff --git a/drivers/net/ngbe/base/ngbe_type.h b/drivers/net/ngbe/base/ngbe_type.h
index 269e087d50..4c995e7397 100644
--- a/drivers/net/ngbe/base/ngbe_type.h
+++ b/drivers/net/ngbe/base/ngbe_type.h
@@ -17,6 +17,9 @@ 
 #define NGBE_MAX_QP               (8)
 #define NGBE_MAX_UTA              128
 
+#define NGBE_PCI_MASTER_DISABLE_TIMEOUT	800
+
+
 #define NGBE_ALIGN		128 /* as intel did */
 #define NGBE_ISB_SIZE		16
 
diff --git a/drivers/net/ngbe/ngbe_ethdev.c b/drivers/net/ngbe/ngbe_ethdev.c
index 8e31234442..30c9e68579 100644
--- a/drivers/net/ngbe/ngbe_ethdev.c
+++ b/drivers/net/ngbe/ngbe_ethdev.c
@@ -950,7 +950,6 @@  ngbe_dev_start(struct rte_eth_dev *dev)
 
 	/* stop adapter */
 	hw->adapter_stopped = 0;
-	ngbe_stop_hw(hw);
 
 	/* reinitialize adapter, this calls reset and start */
 	hw->nb_rx_queues = dev->data->nb_rx_queues;
@@ -961,6 +960,8 @@  ngbe_dev_start(struct rte_eth_dev *dev)
 	hw->mac.start_hw(hw);
 	hw->mac.get_link_status = true;
 
+	ngbe_set_pcie_master(hw, true);
+
 	/* configure PF module if SRIOV enabled */
 	ngbe_pf_host_configure(dev);
 
@@ -1174,6 +1175,8 @@  ngbe_dev_stop(struct rte_eth_dev *dev)
 	rte_intr_efd_disable(intr_handle);
 	rte_intr_vec_list_free(intr_handle);
 
+	ngbe_set_pcie_master(hw, true);
+
 	adapter->rss_reta_updated = 0;
 
 	hw->adapter_stopped = true;
@@ -1202,6 +1205,8 @@  ngbe_dev_close(struct rte_eth_dev *dev)
 
 	ngbe_dev_free_queues(dev);
 
+	ngbe_set_pcie_master(hw, false);
+
 	/* reprogram the RAR[0] in case user changed it. */
 	ngbe_set_rar(hw, 0, hw->mac.addr, 0, true);