958e1b
From 8061ffe654905d1e184b82cb4b4d75647618a0c1 Mon Sep 17 00:00:00 2001
240766
From: Laszlo Ersek <lersek@redhat.com>
240766
Date: Thu, 24 Apr 2014 10:57:23 +0200
240766
Subject: [PATCH 11/12] uhci: UNfix irq routing for RHEL-6 machtypes (RHEL only)
240766
240766
RH-Author: Laszlo Ersek <lersek@redhat.com>
240766
Message-id: <1398337043-4967-1-git-send-email-lersek@redhat.com>
240766
Patchwork-id: 58540
240766
O-Subject: [RHEL-7.0 0day qemu-kvm PATCH] uhci: UNfix irq routing for RHEL-6 machtypes (RHEL only)
240766
Bugzilla: 1085701
240766
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
240766
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
240766
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
240766
240766
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1085701
240766
Brew:     https://brewweb.devel.redhat.com/taskinfo?taskID=7368968
240766
240766
Tested by myself and QE.
240766
240766
(Note that the bulk of the work related to this issue happened in bug
240766
1027565 comments 64 to 74, because QE was experiencing it with the other
240766
(original) issue reported in bug 1027565. Only later did I realize that
240766
bug 1085701 already existed for this specific problem.)
240766
240766
Refer to the following upstream commit, present in v1.2.0 and RHEL-7:
240766
240766
    commit 973002c11460efd3c17fe61a76711a103e30e1f9
240766
    Author: Gerd Hoffmann <kraxel@redhat.com>
240766
    Date:   Fri May 25 12:53:47 2012 +0200
240766
240766
        uhci: fix irq routing
240766
240766
        The multifunction ich9 ehci controller with uhci companions uses a
240766
        different interrupt pin for each function.  The three uhci devices
240766
        get pins A, B and C, whereas ehci uses pin D.  This way the guest
240766
        can assign different IRQ lines to each controller.
240766
240766
        Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
240766
240766
This is a performance optimization so that IRQ sharing can be avoided in
240766
the guest.
240766
240766
Contrarily, the RHEL-6 emulator exclusively assigns pin D to each of the
240766
three devices (see "hw/usb-uhci.c" there):
240766
- usb_uhci_ich9_1_initfn()
240766
- usb_uhci_ich9_2_initfn()
240766
- usb_uhci_ich9_3_initfn()
240766
240766
These init functions call usb_uhci_common_initfn(), which in turn assigns:
240766
240766
    pci_conf[0x3d] = 4; // interrupt pin 3
240766
240766
This mismatch breaks migration for rhel6.x.0 machine types from the
240766
RHEL-6.5 emulator to the RHEL-7.0 one.
240766
240766
For example, considering the uhci1 controller, the guest kernel, started
240766
on the RHEL-6.5 source host, will see pin D advertised, and (according to
240766
the PCI interrupt routing table provided by SeaBIOS) will route it to IRQ
240766
11:
240766
240766
  dmesg:
240766
240766
    uhci_hcd 0000:00:11.0: PCI INT D -> Link[LNKD] -> GSI 11 (level, high)
240766
    -> IRQ 11
240766
240766
  /proc/interrupts:
240766
240766
     10: ... IO-APIC-fasteoi   virtio0
240766
     11: ... IO-APIC-fasteoi   uhci_hcd:usb1
240766
240766
When the same guest kernel, using the same rhel6.5.0 machine type, is
240766
started fresh on the RHEL-7.0 target host, pin A is advertised instead
240766
(and routed to a different IRQ, based on the same table from SeaBIOS):
240766
240766
  dmesg:
240766
240766
    uhci_hcd 0000:00:11.0: PCI INT A -> Link[LNKA] -> GSI 10 (level, high)
240766
    -> IRQ 10
240766
240766
  /proc/interrupts:
240766
240766
     10: ... IO-APIC-fasteoi   uhci_hcd:usb1, virtio0
240766
240766
This is no problem as long as we don't migrate.
240766
240766
When we migrate the rhel6.x.0 machtype guest from the RHEL-6.5 host to the
240766
RHEL-7.0 host, the guest kernel (having booted on the source host) will
240766
expect the interrupts for the UHCI device on pin D / IRQ 11. However, the
240766
target host will inject the interrupts on pin A / IRQ 10. No handler in
240766
the guest kernel will claim such IRQ 10 instances (examples are: HDA or
240766
virtio-balloon), hence IRQ 10 will be disabled.
240766
240766
We can fix this in at least two ways:
240766
(1) Drop the persistent "UHCIState.irq_pin" field, and simply use the pin
240766
    identifier that is stored in (already migrated) PCI config space (at
240766
    offset 0x3d).
240766
(2) Introduce yet another RHEL-6 compatibility knob that selects pin D for
240766
    all three ICH9-UHCI controllers.
240766
240766
Since PCI config space could be write-accessible to the guest, plus it
240766
could originate from an untrusted migration source as well, and we'd use
240766
the setting as a subscript into the s->dev.irq[] array in
240766
uhci_update_irq(), it seems safer to go with (2).
240766
240766
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
240766
---
240766
 include/hw/usb.h  |  4 ++++
240766
 hw/i386/pc_piix.c |  1 +
240766
 hw/usb/hcd-uhci.c | 13 ++++++++++++-
240766
 3 files changed, 17 insertions(+), 1 deletion(-)
240766
240766
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
240766
---
240766
 hw/i386/pc_piix.c |    1 +
240766
 hw/usb/hcd-uhci.c |   13 ++++++++++++-
240766
 include/hw/usb.h  |    4 ++++
240766
 3 files changed, 17 insertions(+), 1 deletions(-)
240766
240766
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
240766
index fea98b6..67d51da 100644
240766
--- a/hw/i386/pc_piix.c
240766
+++ b/hw/i386/pc_piix.c
240766
@@ -955,6 +955,7 @@ static void pc_compat_rhel650(QEMUMachineInitArgs *args)
240766
     has_acpi_build = false;
240766
     gigabyte_align = false;
240766
     shadow_bios_after_incoming = true;
240766
+    ich9_uhci123_irqpin_override = true;
240766
 }
240766
 
240766
 static void pc_init_rhel650(QEMUMachineInitArgs *args)
240766
diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c
240766
index 4fc3410..3380107 100644
240766
--- a/hw/usb/hcd-uhci.c
240766
+++ b/hw/usb/hcd-uhci.c
240766
@@ -187,6 +187,8 @@ typedef struct UHCI_QH {
240766
     uint32_t el_link;
240766
 } UHCI_QH;
240766
 
240766
+bool ich9_uhci123_irqpin_override;
240766
+
240766
 static void uhci_async_cancel(UHCIAsync *async);
240766
 static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td);
240766
 
240766
@@ -1232,7 +1234,16 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
240766
     /* TODO: reset value should be 0. */
240766
     pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
240766
 
240766
-    s->irq_pin = u->info.irq_pin;
240766
+    if (ich9_uhci123_irqpin_override &&
240766
+        u->info.vendor_id == PCI_VENDOR_ID_INTEL &&
240766
+        (u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI1 ||
240766
+         u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI2 ||
240766
+         u->info.device_id == PCI_DEVICE_ID_INTEL_82801I_UHCI3)) {
240766
+        fprintf(stderr, "RHEL-6 compat: %s: irq_pin = 3\n", u->info.name);
240766
+        s->irq_pin = 3;
240766
+    } else {
240766
+        s->irq_pin = u->info.irq_pin;
240766
+    }
240766
     pci_config_set_interrupt_pin(pci_conf, s->irq_pin + 1);
240766
 
240766
     if (s->masterbus) {
240766
diff --git a/include/hw/usb.h b/include/hw/usb.h
240766
index b111be0..5668701 100644
240766
--- a/include/hw/usb.h
240766
+++ b/include/hw/usb.h
240766
@@ -578,4 +578,8 @@ int usb_get_quirks(uint16_t vendor_id, uint16_t product_id,
240766
                    uint8_t interface_class, uint8_t interface_subclass,
240766
                    uint8_t interface_protocol);
240766
 
240766
+
240766
+/* hcd-uhci.c -- RHEL-6 machine type compatibility */
240766
+extern bool ich9_uhci123_irqpin_override;
240766
+
240766
 #endif
240766
-- 
240766
1.7.1
240766