aboutsummaryrefslogtreecommitdiff
path: root/hw/usb/hcd-xhci-pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/usb/hcd-xhci-pci.c')
-rw-r--r--hw/usb/hcd-xhci-pci.c41
1 files changed, 36 insertions, 5 deletions
diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c
index 264d7eb..b93c80b 100644
--- a/hw/usb/hcd-xhci-pci.c
+++ b/hw/usb/hcd-xhci-pci.c
@@ -74,6 +74,7 @@ static bool xhci_pci_intr_raise(XHCIState *xhci, int n, bool level)
}
if (msi_enabled(pci_dev) && level) {
+ n %= msi_nr_vectors_allocated(pci_dev);
msi_notify(pci_dev, n);
return true;
}
@@ -81,6 +82,21 @@ static bool xhci_pci_intr_raise(XHCIState *xhci, int n, bool level)
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)
{
XHCIPciState *s = XHCI_PCI(dev);
@@ -94,7 +110,7 @@ static int xhci_pci_vmstate_post_load(void *opaque, int version_id)
PCIDevice *pci_dev = PCI_DEVICE(s);
int intr;
- for (intr = 0; intr < s->xhci.numintrs; intr++) {
+ for (intr = 0; intr < s->xhci.numintrs; intr++) {
if (s->xhci.intr[intr].msix_used) {
msix_vector_use(pci_dev, intr);
} else {
@@ -118,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);
s->xhci.intr_update = xhci_pci_intr_update;
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)) {
return;
}
@@ -197,17 +216,29 @@ static void xhci_instance_init(Object *obj)
qdev_alias_all_properties(DEVICE(&s->xhci), obj);
}
-static void xhci_class_init(ObjectClass *klass, void *data)
+static const Property xhci_pci_properties[] = {
+ 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_BOOL("conditional-intr-mapping", XHCIPciState,
+ conditional_intr_mapping, false),
+};
+
+static void xhci_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->reset = xhci_pci_reset;
+ device_class_set_legacy_reset(dc, xhci_pci_reset);
dc->vmsd = &vmstate_xhci_pci;
set_bit(DEVICE_CATEGORY_USB, dc->categories);
k->realize = usb_xhci_pci_realize;
k->exit = usb_xhci_pci_exit;
k->class_id = PCI_CLASS_SERIAL_USB;
+ 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 = {
@@ -217,14 +248,14 @@ static const TypeInfo xhci_pci_info = {
.class_init = xhci_class_init,
.instance_init = xhci_instance_init,
.abstract = true,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ INTERFACE_PCIE_DEVICE },
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
{ }
},
};
-static void qemu_xhci_class_init(ObjectClass *klass, void *data)
+static void qemu_xhci_class_init(ObjectClass *klass, const void *data)
{
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);