|
@@ -82,6 +82,21 @@ static bool xhci_pci_intr_raise(XHCIState *xhci, int n, bool level)
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static bool xhci_pci_intr_mapping_conditional(XHCIState *xhci)
|
|
|
|
+{
|
|
|
|
+ XHCIPciState *s = container_of(xhci, XHCIPciState, xhci);
|
|
|
|
+ PCIDevice *pci_dev = PCI_DEVICE(s);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Implementation of the "conditional-intr-mapping" property, which only
|
|
|
|
+ * enables interrupter mapping if MSI or MSI-X is available and active.
|
|
|
|
+ * Forces all events onto interrupter/event ring 0 in pin-based IRQ mode.
|
|
|
|
+ * Provides compatibility with macOS guests on machine types where MSI(-X)
|
|
|
|
+ * is not available.
|
|
|
|
+ */
|
|
|
|
+ return msix_enabled(pci_dev) || msi_enabled(pci_dev);
|
|
|
|
+}
|
|
|
|
+
|
|
static void xhci_pci_reset(DeviceState *dev)
|
|
static void xhci_pci_reset(DeviceState *dev)
|
|
{
|
|
{
|
|
XHCIPciState *s = XHCI_PCI(dev);
|
|
XHCIPciState *s = XHCI_PCI(dev);
|
|
@@ -119,6 +134,9 @@ static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp)
|
|
object_property_set_link(OBJECT(&s->xhci), "host", OBJECT(s), NULL);
|
|
object_property_set_link(OBJECT(&s->xhci), "host", OBJECT(s), NULL);
|
|
s->xhci.intr_update = xhci_pci_intr_update;
|
|
s->xhci.intr_update = xhci_pci_intr_update;
|
|
s->xhci.intr_raise = xhci_pci_intr_raise;
|
|
s->xhci.intr_raise = xhci_pci_intr_raise;
|
|
|
|
+ if (s->conditional_intr_mapping) {
|
|
|
|
+ s->xhci.intr_mapping_supported = xhci_pci_intr_mapping_conditional;
|
|
|
|
+ }
|
|
if (!qdev_realize(DEVICE(&s->xhci), NULL, errp)) {
|
|
if (!qdev_realize(DEVICE(&s->xhci), NULL, errp)) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -201,6 +219,8 @@ static void xhci_instance_init(Object *obj)
|
|
static const Property xhci_pci_properties[] = {
|
|
static const Property xhci_pci_properties[] = {
|
|
DEFINE_PROP_ON_OFF_AUTO("msi", XHCIPciState, msi, ON_OFF_AUTO_AUTO),
|
|
DEFINE_PROP_ON_OFF_AUTO("msi", XHCIPciState, msi, ON_OFF_AUTO_AUTO),
|
|
DEFINE_PROP_ON_OFF_AUTO("msix", XHCIPciState, msix, ON_OFF_AUTO_AUTO),
|
|
DEFINE_PROP_ON_OFF_AUTO("msix", XHCIPciState, msix, ON_OFF_AUTO_AUTO),
|
|
|
|
+ DEFINE_PROP_BOOL("conditional-intr-mapping", XHCIPciState,
|
|
|
|
+ conditional_intr_mapping, false),
|
|
};
|
|
};
|
|
|
|
|
|
static void xhci_class_init(ObjectClass *klass, void *data)
|
|
static void xhci_class_init(ObjectClass *klass, void *data)
|
|
@@ -215,6 +235,10 @@ static void xhci_class_init(ObjectClass *klass, void *data)
|
|
k->exit = usb_xhci_pci_exit;
|
|
k->exit = usb_xhci_pci_exit;
|
|
k->class_id = PCI_CLASS_SERIAL_USB;
|
|
k->class_id = PCI_CLASS_SERIAL_USB;
|
|
device_class_set_props(dc, xhci_pci_properties);
|
|
device_class_set_props(dc, xhci_pci_properties);
|
|
|
|
+ object_class_property_set_description(klass, "conditional-intr-mapping",
|
|
|
|
+ "When true, disables interrupter mapping for pin-based IRQ mode. "
|
|
|
|
+ "Intended to be used with guest drivers with questionable behaviour, "
|
|
|
|
+ "such as macOS's.");
|
|
}
|
|
}
|
|
|
|
|
|
static const TypeInfo xhci_pci_info = {
|
|
static const TypeInfo xhci_pci_info = {
|