+static int
+hns3vf_restore_conf(struct hns3_adapter *hns)
+{
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ ret = hns3vf_configure_mac_addr(hns, false);
+ if (ret)
+ return ret;
+
+ ret = hns3vf_configure_all_mc_mac_addr(hns, false);
+ if (ret)
+ goto err_mc_mac;
+
+ ret = hns3vf_restore_vlan_conf(hns);
+ if (ret)
+ goto err_vlan_table;
+
+ if (hw->adapter_state == HNS3_NIC_STARTED) {
+ ret = hns3vf_do_start(hns, false);
+ if (ret)
+ goto err_vlan_table;
+ hns3_info(hw, "hns3vf dev restart successful!");
+ } else if (hw->adapter_state == HNS3_NIC_STOPPING)
+ hw->adapter_state = HNS3_NIC_CONFIGURED;
+ return 0;
+
+err_vlan_table:
+ hns3vf_configure_all_mc_mac_addr(hns, true);
+err_mc_mac:
+ hns3vf_configure_mac_addr(hns, true);
+ return ret;
+}
+
+static enum hns3_reset_level
+hns3vf_get_reset_level(struct hns3_hw *hw, uint64_t *levels)
+{
+ enum hns3_reset_level reset_level;
+
+ /* return the highest priority reset level amongst all */
+ if (hns3_atomic_test_bit(HNS3_VF_RESET, levels))
+ reset_level = HNS3_VF_RESET;
+ else if (hns3_atomic_test_bit(HNS3_VF_FULL_RESET, levels))
+ reset_level = HNS3_VF_FULL_RESET;
+ else if (hns3_atomic_test_bit(HNS3_VF_PF_FUNC_RESET, levels))
+ reset_level = HNS3_VF_PF_FUNC_RESET;
+ else if (hns3_atomic_test_bit(HNS3_VF_FUNC_RESET, levels))
+ reset_level = HNS3_VF_FUNC_RESET;
+ else if (hns3_atomic_test_bit(HNS3_FLR_RESET, levels))
+ reset_level = HNS3_FLR_RESET;
+ else
+ reset_level = HNS3_NONE_RESET;
+
+ if (hw->reset.level != HNS3_NONE_RESET && reset_level < hw->reset.level)
+ return HNS3_NONE_RESET;
+
+ return reset_level;
+}
+
+static void
+hns3vf_reset_service(void *param)
+{
+ struct hns3_adapter *hns = (struct hns3_adapter *)param;
+ struct hns3_hw *hw = &hns->hw;
+ enum hns3_reset_level reset_level;
+ struct timeval tv_delta;
+ struct timeval tv_start;
+ struct timeval tv;
+ uint64_t msec;
+
+ /*
+ * The interrupt is not triggered within the delay time.
+ * The interrupt may have been lost. It is necessary to handle
+ * the interrupt to recover from the error.
+ */
+ if (rte_atomic16_read(&hns->hw.reset.schedule) == SCHEDULE_DEFERRED) {
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_REQUESTED);
+ hns3_err(hw, "Handling interrupts in delayed tasks");
+ hns3vf_interrupt_handler(&rte_eth_devices[hw->data->port_id]);
+ reset_level = hns3vf_get_reset_level(hw, &hw->reset.pending);
+ if (reset_level == HNS3_NONE_RESET) {
+ hns3_err(hw, "No reset level is set, try global reset");
+ hns3_atomic_set_bit(HNS3_VF_RESET, &hw->reset.pending);
+ }
+ }
+ rte_atomic16_set(&hns->hw.reset.schedule, SCHEDULE_NONE);
+
+ /*
+ * Hardware reset has been notified, we now have to poll & check if
+ * hardware has actually completed the reset sequence.
+ */
+ reset_level = hns3vf_get_reset_level(hw, &hw->reset.pending);
+ if (reset_level != HNS3_NONE_RESET) {
+ gettimeofday(&tv_start, NULL);
+ hns3_reset_process(hns, reset_level);
+ gettimeofday(&tv, NULL);
+ timersub(&tv, &tv_start, &tv_delta);
+ msec = tv_delta.tv_sec * MSEC_PER_SEC +
+ tv_delta.tv_usec / USEC_PER_MSEC;
+ if (msec > HNS3_RESET_PROCESS_MS)
+ hns3_err(hw, "%d handle long time delta %" PRIx64
+ " ms time=%ld.%.6ld",
+ hw->reset.level, msec, tv.tv_sec, tv.tv_usec);
+ }
+}
+
+static int
+hns3vf_reinit_dev(struct hns3_adapter *hns)
+{
+ struct rte_eth_dev *eth_dev = &rte_eth_devices[hns->hw.data->port_id];
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(eth_dev);
+ struct hns3_hw *hw = &hns->hw;
+ int ret;
+
+ if (hw->reset.level == HNS3_VF_FULL_RESET) {
+ rte_intr_disable(&pci_dev->intr_handle);
+ hns3vf_set_bus_master(pci_dev, true);
+ }
+
+ /* Firmware command initialize */
+ ret = hns3_cmd_init(hw);
+ if (ret) {
+ hns3_err(hw, "Failed to init cmd: %d", ret);
+ goto err_cmd_init;
+ }
+
+ if (hw->reset.level == HNS3_VF_FULL_RESET) {
+ /*
+ * UIO enables msix by writing the pcie configuration space
+ * vfio_pci enables msix in rte_intr_enable.
+ */
+ if (pci_dev->kdrv == RTE_KDRV_IGB_UIO ||
+ pci_dev->kdrv == RTE_KDRV_UIO_GENERIC) {
+ if (hns3vf_enable_msix(pci_dev, true))
+ hns3_err(hw, "Failed to enable msix");
+ }
+
+ rte_intr_enable(&pci_dev->intr_handle);
+ }
+
+ ret = hns3_reset_all_queues(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to reset all queues: %d", ret);
+ goto err_init;
+ }
+
+ ret = hns3vf_init_hardware(hns);
+ if (ret) {
+ hns3_err(hw, "Failed to init hardware: %d", ret);
+ goto err_init;
+ }
+
+ return 0;
+
+err_cmd_init:
+ hns3vf_set_bus_master(pci_dev, false);
+err_init:
+ hns3_cmd_uninit(hw);
+ return ret;
+}
+