Author: royger
Date: Mon Aug  4 09:01:21 2014
New Revision: 269513
URL: http://svnweb.freebsd.org/changeset/base/269513

Log:
  xen: implement support for mapping IO APIC interrupts on Xen
  
  Allow a privileged Xen guest (Dom0) to parse the MADT ACPI interrupt
  overrides and register them with the interrupt subsystem.
  
  Also add a Xen specific implementation for bus_config_intr that
  registers interrupts on demand for all the vectors less than
  FIRST_MSI_INT.
  
  Sponsored by: Citrix Systems R&D
  
  x86/xen/pvcpu_enum.c:
   - Use helper functions from x86/acpica/madt.c in order to parse
     interrupt overrides from the MADT.
   - Walk the MADT and register any interrupt override with the
     interrupt subsystem.
  
  x86/xen/xen_nexus.c:
   - Add a custom bus_config_intr method for Xen that intercepts calls
     to configure unset interrupts and registers them on the fly (if the
     vector is < FIRST_MSI_INT).

Modified:
  head/sys/x86/xen/pvcpu_enum.c
  head/sys/x86/xen/xen_nexus.c

Modified: head/sys/x86/xen/pvcpu_enum.c
==============================================================================
--- head/sys/x86/xen/pvcpu_enum.c       Mon Aug  4 08:58:50 2014        
(r269512)
+++ head/sys/x86/xen/pvcpu_enum.c       Mon Aug  4 09:01:21 2014        
(r269513)
@@ -44,15 +44,25 @@ __FBSDID("$FreeBSD$");
 #include <machine/smp.h>
 
 #include <xen/xen-os.h>
+#include <xen/xen_intr.h>
 #include <xen/hypervisor.h>
 
 #include <xen/interface/vcpu.h>
 
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/actables.h>
+
+#include <dev/acpica/acpivar.h>
+
 static int xenpv_probe(void);
 static int xenpv_probe_cpus(void);
 static int xenpv_setup_local(void);
 static int xenpv_setup_io(void);
 
+static ACPI_TABLE_MADT *madt;
+static vm_paddr_t madt_physaddr;
+static vm_offset_t madt_length;
+
 static struct apic_enumerator xenpv_enumerator = {
        "Xen PV",
        xenpv_probe,
@@ -61,6 +71,55 @@ static struct apic_enumerator xenpv_enum
        xenpv_setup_io
 };
 
+/*--------------------- Helper functions to parse MADT 
-----------------------*/
+
+/*
+ * Parse an interrupt source override for an ISA interrupt.
+ */
+static void
+madt_parse_interrupt_override(ACPI_MADT_INTERRUPT_OVERRIDE *intr)
+{
+       enum intr_trigger trig;
+       enum intr_polarity pol;
+
+       if (acpi_quirks & ACPI_Q_MADT_IRQ0 && intr->SourceIrq == 0 &&
+           intr->GlobalIrq == 2) {
+               if (bootverbose)
+                       printf("MADT: Skipping timer override\n");
+               return;
+       }
+
+       madt_parse_interrupt_values(intr, &trig, &pol);
+
+       /* Register the IRQ with the polarity and trigger mode found. */
+       xen_register_pirq(intr->GlobalIrq, trig, pol);
+}
+
+/*
+ * Call the handler routine for each entry in the MADT table.
+ */
+static void
+madt_walk_table(acpi_subtable_handler *handler, void *arg)
+{
+
+       acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
+           handler, arg);
+}
+
+/*
+ * Parse interrupt entries.
+ */
+static void
+madt_parse_ints(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
+{
+
+       if (entry->Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE)
+               madt_parse_interrupt_override(
+                   (ACPI_MADT_INTERRUPT_OVERRIDE *)entry);
+}
+
+/*---------------------------- Xen PV enumerator 
-----------------------------*/
+
 /*
  * This enumerator will only be registered on PVH
  */
@@ -105,6 +164,40 @@ xenpv_setup_local(void)
 static int
 xenpv_setup_io(void)
 {
+
+       if (xen_initial_domain()) {
+               int i;
+
+               /* Map MADT */
+               madt_physaddr = acpi_find_table(ACPI_SIG_MADT);
+               madt = acpi_map_table(madt_physaddr, ACPI_SIG_MADT);
+               madt_length = madt->Header.Length;
+
+               /* Try to initialize ACPI so that we can access the FADT. */
+               i = acpi_Startup();
+               if (ACPI_FAILURE(i)) {
+                       printf("MADT: ACPI Startup failed with %s\n",
+                           AcpiFormatException(i));
+                       printf("Try disabling either ACPI or apic support.\n");
+                       panic("Using MADT but ACPI doesn't work");
+               }
+
+               /* Run through the table to see if there are any overrides. */
+               madt_walk_table(madt_parse_ints, NULL);
+
+               /*
+                * If there was not an explicit override entry for the SCI,
+                * force it to use level trigger and active-low polarity.
+                */
+               if (!madt_found_sci_override) {
+                       printf(
+       "MADT: Forcing active-low polarity and level trigger for SCI\n");
+                       xen_register_pirq(AcpiGbl_FADT.SciInterrupt,
+                           INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
+               }
+
+               acpi_SetDefaultIntrModel(ACPI_INTR_APIC);
+       }
        return (0);
 }
 

Modified: head/sys/x86/xen/xen_nexus.c
==============================================================================
--- head/sys/x86/xen/xen_nexus.c        Mon Aug  4 08:58:50 2014        
(r269512)
+++ head/sys/x86/xen/xen_nexus.c        Mon Aug  4 09:01:21 2014        
(r269513)
@@ -36,8 +36,10 @@ __FBSDID("$FreeBSD$");
 #include <sys/smp.h>
 
 #include <machine/nexusvar.h>
+#include <machine/intr_machdep.h>
 
 #include <xen/xen-os.h>
+#include <xen/xen_intr.h>
 
 /*
  * Xen nexus(4) driver.
@@ -63,11 +65,33 @@ nexus_xen_attach(device_t dev)
        return (0);
 }
 
+static int
+nexus_xen_config_intr(device_t dev, int irq, enum intr_trigger trig,
+    enum intr_polarity pol)
+{
+       int ret;
+
+       /*
+        * ISA and PCI intline IRQs are not preregistered on Xen, so
+        * intercept calls to configure those and register them on the fly.
+        */
+       if ((irq < FIRST_MSI_INT) && (intr_lookup_source(irq) == NULL)) {
+               ret = xen_register_pirq(irq, trig, pol);
+               if (ret != 0)
+                       return (ret);
+               nexus_add_irq(irq);
+       }
+       return (intr_config_intr(irq, trig, pol));
+}
+
 static device_method_t nexus_xen_methods[] = {
        /* Device interface */
        DEVMETHOD(device_probe,         nexus_xen_probe),
        DEVMETHOD(device_attach,        nexus_xen_attach),
 
+       /* INTR */
+       DEVMETHOD(bus_config_intr,      nexus_xen_config_intr),
+
        { 0, 0 }
 };
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to