@@ -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
@@ -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);
@@ -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;
@@ -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_ */
@@ -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 */
@@ -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
@@ -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);