@@ -423,12 +423,21 @@ static uint8_t pci_find_cap_offset(PCIDevice *d, uint8_t cap, uint8_t start)
return 0;
}
+static uint32_t calc_assigned_dev_id(uint16_t seg, uint8_t bus, uint8_t devfn)
+{
+ return (uint32_t)seg << 16 | (uint32_t)bus << 8 | (uint32_t)devfn;
+}
+
static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
uint32_t val, int len)
{
int fd;
ssize_t ret;
AssignedDevice *pci_dev = container_of(d, AssignedDevice, dev);
+ struct kvm_assigned_pci_dev assigned_dev_data;
+#ifdef KVM_CAP_PCI_2_3
+ bool intx_masked, update_intx_mask;
+#endif /* KVM_CAP_PCI_2_3 */
DEBUG("(%x.%x): address=%04x val=0x%08x len=%d\n",
((d->devfn >> 3) & 0x1F), (d->devfn & 0x7),
@@ -439,6 +448,26 @@ static void assigned_dev_pci_write_config(PCIDevice *d, uint32_t address,
}
if (ranges_overlap(address, len, PCI_COMMAND, 2)) {
+#ifdef KVM_CAP_PCI_2_3
+ update_intx_mask = false;
+ if (address == PCI_COMMAND+1) {
+ intx_masked = val & (PCI_COMMAND_INTX_DISABLE >> 8);
+ update_intx_mask = true;
+ } else if (len >= 2) {
+ intx_masked = val & PCI_COMMAND_INTX_DISABLE;
+ update_intx_mask = true;
+ }
+ if (update_intx_mask) {
+ memset(&assigned_dev_data, 0, sizeof(assigned_dev_data));
+ assigned_dev_data.assigned_dev_id =
+ calc_assigned_dev_id(pci_dev->h_segnr, pci_dev->h_busnr,
+ pci_dev->h_devfn);
+ if (intx_masked) {
+ assigned_dev_data.flags = KVM_DEV_ASSIGN_MASK_INTX;
+ }
+ kvm_assign_set_intx_mask(kvm_context, &assigned_dev_data);
+ }
+#endif /* KVM_CAP_PCI_2_3 */
pci_default_write_config(d, address, val, len);
/* Continue to program the card */
}
@@ -876,11 +905,6 @@ static void free_assigned_device(AssignedDevice *dev)
}
}
-static uint32_t calc_assigned_dev_id(uint16_t seg, uint8_t bus, uint8_t devfn)
-{
- return (uint32_t)seg << 16 | (uint32_t)bus << 8 | (uint32_t)devfn;
-}
-
static void assign_failed_examine(AssignedDevice *dev)
{
char name[PATH_MAX], dir[PATH_MAX], driver[PATH_MAX] = {}, *ns;
@@ -971,6 +995,10 @@ static int assign_device(AssignedDevice *dev)
"cause host memory corruption if the device issues DMA write "
"requests!\n");
}
+#ifdef KVM_CAP_PCI_2_3
+ assigned_dev_data.flags |= KVM_DEV_ASSIGN_PCI_2_3;
+ dev->emulate_cmd_mask |= PCI_COMMAND_INTX_DISABLE;
+#endif /* KVM_CAP_PCI_2_3 */
r = kvm_assign_pci_device(kvm_context, &assigned_dev_data);
if (r < 0) {
@@ -740,6 +740,14 @@ int kvm_deassign_pci_device(kvm_context_t kvm,
}
#endif
+#ifdef KVM_CAP_PCI_2_3
+int kvm_assign_set_intx_mask(kvm_context_t kvm,
+ struct kvm_assigned_pci_dev *assigned_dev)
+{
+ return kvm_vm_ioctl(kvm_state, KVM_ASSIGN_SET_INTX_MASK, assigned_dev);
+}
+#endif
+
int kvm_reinject_control(kvm_context_t kvm, int pit_reinject)
{
#ifdef KVM_CAP_REINJECT_CONTROL
@@ -602,6 +602,9 @@ int kvm_assign_set_msix_entry(kvm_context_t kvm,
struct kvm_assigned_msix_entry *entry);
#endif
+int kvm_assign_set_intx_mask(kvm_context_t kvm,
+ struct kvm_assigned_pci_dev *assigned_dev);
+
#else /* !CONFIG_KVM */
typedef struct kvm_context *kvm_context_t;