+static clib_error_t *
+_vlib_pci_config_set_control_bit (vlib_main_t *vm, vlib_pci_dev_handle_t h,
+ u16 bit, int new_val, int *already_set)
+{
+ u16 control, old;
+ clib_error_t *err;
+
+ err = vlib_pci_read_write_config (
+ vm, h, VLIB_READ, STRUCT_OFFSET_OF (vlib_pci_config_t, command), &old,
+ STRUCT_SIZE_OF (vlib_pci_config_t, command));
+
+ if (err)
+ return err;
+
+ control = new_val ? old | bit : old & ~bit;
+ *already_set = old == control;
+ if (*already_set)
+ return 0;
+
+ return vlib_pci_read_write_config (
+ vm, h, VLIB_WRITE, STRUCT_OFFSET_OF (vlib_pci_config_t, command), &control,
+ STRUCT_SIZE_OF (vlib_pci_config_t, command));
+}
+
+clib_error_t *
+vlib_pci_intr_enable (vlib_main_t *vm, vlib_pci_dev_handle_t h)
+{
+ const vlib_pci_config_reg_command_t cmd = { .intx_disable = 1 };
+ clib_error_t *err;
+ int already_set;
+
+ err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 0, &already_set);
+ log_debug (h, "interrupt%senabled", already_set ? " " : " already ");
+ return err;
+}
+
+clib_error_t *
+vlib_pci_intr_disable (vlib_main_t *vm, vlib_pci_dev_handle_t h)
+{
+ const vlib_pci_config_reg_command_t cmd = { .intx_disable = 1 };
+ clib_error_t *err;
+ int already_set;
+
+ err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 1, &already_set);
+ log_debug (h, "interrupt%sdisabled", already_set ? " " : " already ");
+ return err;
+}
+
+clib_error_t *
+vlib_pci_bus_master_enable (vlib_main_t *vm, vlib_pci_dev_handle_t h)
+{
+ const vlib_pci_config_reg_command_t cmd = { .bus_master = 1 };
+ clib_error_t *err;
+ int already_set;
+
+ err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 1, &already_set);
+ log_debug (h, "bus-master%senabled", already_set ? " " : " already ");
+ return err;
+}
+
+clib_error_t *
+vlib_pci_bus_master_disable (vlib_main_t *vm, vlib_pci_dev_handle_t h)
+{
+ const vlib_pci_config_reg_command_t cmd = { .bus_master = 1 };
+ clib_error_t *err;
+ int already_set;
+
+ err = _vlib_pci_config_set_control_bit (vm, h, cmd.as_u16, 0, &already_set);
+ log_debug (h, "bus-master%sdisabled", already_set ? " " : " already ");
+ return err;
+}
+
+clib_error_t *
+vlib_pci_function_level_reset (vlib_main_t *vm, vlib_pci_dev_handle_t h)
+{
+ vlib_pci_config_t cfg;
+ pci_capability_pcie_t *cap;
+ pci_capability_pcie_dev_control_t dev_control;
+ clib_error_t *err;
+ u8 offset;
+
+ log_debug (h, "function level reset");
+
+ err = vlib_pci_read_write_config (vm, h, VLIB_READ, 0, &cfg, sizeof (cfg));
+ if (err)
+ return err;
+
+ offset = cfg.cap_ptr;
+ do
+ {
+ cap = (pci_capability_pcie_t *) (cfg.data + offset);
+
+ if (cap->capability_id == PCI_CAP_ID_PCIE)
+ break;
+
+ offset = cap->next_offset;
+ }
+ while (offset);
+
+ if (cap->capability_id != PCI_CAP_ID_PCIE)
+ return clib_error_return (0, "PCIe capability config not found");
+
+ if (cap->dev_caps.flr_capable == 0)
+ return clib_error_return (0, "PCIe function level reset not supported");
+
+ dev_control = cap->dev_control;
+ dev_control.function_level_reset = 1;
+
+ if ((err = vlib_pci_write_config_u16 (
+ vm, h, offset + STRUCT_OFFSET_OF (pci_capability_pcie_t, dev_control),
+ &dev_control.as_u16)))
+ return err;
+
+ return 0;
+}
+