2548
return true;
2549
}
2550
2551
-static void vfio_add_ext_cap(VFIOPCIDevice *vdev)
2551
+/*
2552
+ * Determine whether ATS capability should be advertised for @vdev, based on
2553
+ * whether it was enabled on the command line and whether it is supported
2554
+ * according to the kernel.
2555
+ *
2556
+ * Store whether ATS capability should be advertised in @ats_needed.
2557
+ *
2558
+ * Returns false only when ats=on is explicitly requested but the kernel
2559
+ * reports it is not supported. Returns true in all other cases.
2560
+ */
2561
+static bool vfio_pci_ats_requested_and_supported(VFIOPCIDevice *vdev,
2562
+ bool *ats_needed, Error **errp)
2563
+{
2564
+ HostIOMMUDevice *hiod = vdev->vbasedev.hiod;
2565
+ HostIOMMUDeviceClass *hiodc;
2566
+ bool ats_supported;
2567
+ *ats_needed = false;
2568
+
2569
+ if (vdev->ats == ON_OFF_AUTO_OFF) {
2570
+ return true;
2571
+ }
2572
+
2573
+ *ats_needed = true;
2574
+ if (!hiod) {
2575
+ return true;
2576
+ }
2577
+ hiodc = HOST_IOMMU_DEVICE_GET_CLASS(hiod);
2578
+ if (!hiodc || !hiodc->support_ats) {
2579
+ return true;
2580
+ }
2581
+
2582
+ ats_supported = hiodc->support_ats(hiod);
2583
+ if (vdev->ats == ON_OFF_AUTO_ON && !ats_supported) {
2584
+ error_setg(errp, "vfio-pci: ATS requested but not supported by kernel");
2585
+ *ats_needed = false;
2586
+ return false;
2587
+ }
2588
+
2589
+ *ats_needed = ats_supported;
2590
+ return true;
2591
+}
2592
+
2593
+static void vfio_add_ext_cap(VFIOPCIDevice *vdev, bool ats_needed)
2594
{
2595
PCIDevice *pdev = PCI_DEVICE(vdev);
2596
bool pasid_cap_added = false;
2597
+ bool ats_cap_present = false;
2598
Error *err = NULL;
2599
uint32_t header;
2600
uint16_t cap_id, next, size;
2680
*/
2681
case PCI_EXT_CAP_ID_PASID:
2682
pasid_cap_added = true;
2640
- /* fallthrough */
2683
+ pcie_add_capability(pdev, cap_id, cap_ver, next, size);
2684
+ break;
2685
+ case PCI_EXT_CAP_ID_ATS:
2686
+ ats_cap_present = true;
2687
+ /*
2688
+ * If ATS is requested and supported according to the kernel, add
2689
+ * the ATS capability. If not supported according to the kernel or
2690
+ * disabled on the qemu command line, omit the ATS cap.
2691
+ */
2692
+ if (ats_needed) {
2693
+ pcie_add_capability(pdev, cap_id, cap_ver, next, size);
2694
+ }
2695
+ break;
2696
default:
2697
pcie_add_capability(pdev, cap_id, cap_ver, next, size);
2698
}
2703
error_report_err(err);
2704
}
2705
2706
+ if (vdev->ats == ON_OFF_AUTO_ON && !ats_cap_present) {
2707
+ warn_report("vfio-pci: ats=on requested, but host device has no "
2708
+ "ATS extended capability");
2709
+ }
2710
+
2711
+ if (vdev->ats == ON_OFF_AUTO_AUTO && ats_cap_present && !ats_needed) {
2712
+ warn_report("vfio-pci: host kernel reports ATS unsupported; "
2713
+ "ATS capability will be masked");
2714
+ }
2715
+
2716
/* Cleanup chain head ID if necessary */
2717
if (pci_get_word(pdev->config + PCI_CONFIG_SPACE_SIZE) == 0xFFFF) {
2718
pci_set_word(pdev->config + PCI_CONFIG_SPACE_SIZE, 0);
2724
bool vfio_pci_add_capabilities(VFIOPCIDevice *vdev, Error **errp)
2725
{
2726
PCIDevice *pdev = PCI_DEVICE(vdev);
2727
+ bool ats_needed = false;
2728
2729
if (!(pdev->config[PCI_STATUS] & PCI_STATUS_CAP_LIST) ||
2730
!pdev->config[PCI_CAPABILITY_LIST]) {
2735
return false;
2736
}
2737
2672
- vfio_add_ext_cap(vdev);
2738
+ if (!vfio_pci_ats_requested_and_supported(vdev, &ats_needed, errp)) {
2739
+ return false;
2740
+ }
2741
+
2742
+ vfio_add_ext_cap(vdev, ats_needed);
2743
return true;
2744
}
2745
3889
DEFINE_PROP_BOOL("skip-vsc-check", VFIOPCIDevice, skip_vsc_check, true),
3890
DEFINE_PROP_UINT16("x-vpasid-cap-offset", VFIOPCIDevice,
3891
vpasid_cap_offset, 0),
3892
+ DEFINE_PROP_ON_OFF_AUTO("ats", VFIOPCIDevice, ats, ON_OFF_AUTO_AUTO),
3893
};
3894
3895
static void vfio_pci_set_fd(Object *obj, const char *str, Error **errp)
4041
"destination when doing live "
4042
"migration of device state via "
4043
"multifd channels");
3973
- object_class_property_set_description(klass, /* 11.0 */
4044
+ object_class_property_set_description(klass, /* 11.0 */
4045
"x-vpasid-cap-offset",
4046
"PCIe extended configuration space offset at which to place a "
4047
"synthetic PASID extended capability when PASID is enabled via "
4048
"a vIOMMU. A value of 0 (default) places the capability at the "
4049
"end of the extended configuration space. The offset must be "
4050
"4-byte aligned and within the PCIe extended configuration space");
4051
+ object_class_property_set_description(klass, /* 11.1 */
4052
+ "ats",
4053
+ "Control guest visibility of the ATS PCIe extended capability. "
4054
+ "Valid values are on, off, and auto (default). "
4055
+ "'off' always masks ATS. "
4056
+ "'on' requires ATS support for the device and fails realize if the "
4057
+ "host kernel reports ATS as unavailable for this device. "
4058
+ "'auto' masks ATS only when the host kernel reports "
4059
+ "ATS as unavailable");
4060
}
4061
4062
static const TypeInfo vfio_pci_info = {