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: sta...@dpdk.org

Signed-off-by: Jiawen Wu <jiawe...@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(-)

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);
 
-- 
2.21.0.windows.1



Reply via email to