[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH RFC 3/6] xen/arm: Allow platforms to hook IRQ routing.



From: "Kyle J. Temkin" <temkink@xxxxxxxxxxxx>

Some common platforms (e.g. Tegra) have non-traditional IRQ controllers
that must be programmed in addition to their primary GICs-- and which
can come in unusual topologies. Device trees for targets that feature
these controllers often deviate from the conventions that Xen expects.

This commit provides a foundation for support of these platforms, by:
- Allowing the platform to decide which IRQs can be routed by Xen,
  rather than assuming that only GIC-connected IRQs can be routed.
- Allowing the platform to extend/replace existing IRQ routing logic,
  rather than asssuming that the GIC will always be programmed to route
  IRQs.
- Allows the platform to override IRQ translation, rather than assuming
  GIC translation will always be followed. This is useful in cases where
  device tree IRQ numbers don't correspond to GIC IRQ numbers.

Signed-off-by: Kyle Temkin <temkink@xxxxxxxxxxxx>
---
 xen/arch/arm/domain_build.c        | 14 +++++++++-----
 xen/arch/arm/irq.c                 |  5 +++--
 xen/arch/arm/platform.c            | 39 ++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/time.c                |  2 +-
 xen/drivers/char/cadence-uart.c    |  3 ++-
 xen/drivers/char/exynos4210-uart.c |  3 ++-
 xen/drivers/char/ns16550.c         |  3 ++-
 xen/drivers/char/omap-uart.c       |  3 ++-
 xen/drivers/char/pl011.c           |  3 ++-
 xen/drivers/char/scif-uart.c       |  3 ++-
 xen/drivers/passthrough/arm/smmu.c |  4 ++--
 xen/include/asm-arm/platform.h     | 14 ++++++++++++++
 12 files changed, 80 insertions(+), 16 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 52c9a01..402c766 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1094,16 +1094,20 @@ static int handle_device(struct domain *d, struct 
dt_device_node *dev)
 
         /*
          * Don't map IRQ that have no physical meaning
-         * ie: IRQ whose controller is not the GIC
+         * ie: IRQ that does not wind up being controlled by the GIC
+         * (Note that we can't just check to see if an IRQ is owned by the GIC,
+         *  as some platforms have a controller between the device irq and the 
GIC,
+         *  such as the Tegra legacy interrupt controller.)
          */
-        if ( rirq.controller != dt_interrupt_controller )
+        if ( !platform_irq_is_routable(&rirq) )
         {
-            dt_dprintk("irq %u not connected to primary controller. Connected 
to %s\n",
-                      i, dt_node_full_name(rirq.controller));
+            dt_dprintk("irq %u not (directly or indirectly) connected to 
primary"
+                        "controller. Connected to %s\n", i,
+                        dt_node_full_name(rirq.controller));
             continue;
         }
 
-        res = platform_get_irq(dev, i);
+        res = platform_irq_for_device(dev, i);
         if ( res < 0 )
         {
             printk(XENLOG_ERR "Unable to get irq %u for %s\n",
diff --git a/xen/arch/arm/irq.c b/xen/arch/arm/irq.c
index 06d4843..dc42817 100644
--- a/xen/arch/arm/irq.c
+++ b/xen/arch/arm/irq.c
@@ -27,6 +27,7 @@
 
 #include <asm/gic.h>
 #include <asm/vgic.h>
+#include <asm/platform.h>
 
 static unsigned int local_irqs_type[NR_LOCAL_IRQS];
 static DEFINE_SPINLOCK(local_irqs_type_lock);
@@ -370,7 +371,7 @@ int setup_irq(unsigned int irq, unsigned int irqflags, 
struct irqaction *new)
     /* First time the IRQ is setup */
     if ( disabled )
     {
-        gic_route_irq_to_xen(desc, GIC_PRI_IRQ);
+        platform_route_irq_to_xen(desc, GIC_PRI_IRQ);
         /* It's fine to use smp_processor_id() because:
          * For PPI: irq_desc is banked
          * For SPI: we don't care for now which CPU will receive the
@@ -504,7 +505,7 @@ int route_irq_to_guest(struct domain *d, unsigned int virq,
     if ( retval )
         goto out;
 
-    retval = gic_route_irq_to_guest(d, virq, desc, GIC_PRI_IRQ);
+    retval = platform_route_irq_to_guest(d, virq, desc, GIC_PRI_IRQ);
 
     spin_unlock_irqrestore(&desc->lock, flags);
 
diff --git a/xen/arch/arm/platform.c b/xen/arch/arm/platform.c
index b0bfaa9..74abdc6 100644
--- a/xen/arch/arm/platform.c
+++ b/xen/arch/arm/platform.c
@@ -137,6 +137,45 @@ bool_t platform_device_is_blacklisted(const struct 
dt_device_node *node)
     return (dt_match_node(blacklist, node) != NULL);
 }
 
+int platform_route_irq_to_guest(struct domain *d, unsigned int virq,
+                                struct irq_desc *desc, unsigned int priority)
+{
+    if ( platform && platform->route_irq_to_guest )
+        return platform->route_irq_to_guest(d, virq, desc, priority);
+    else
+        return gic_route_irq_to_guest(d, virq, desc, priority);
+}
+
+void platform_route_irq_to_xen(struct irq_desc *desc, unsigned int priority)
+{
+    if ( platform && platform->route_irq_to_xen )
+        platform->route_irq_to_xen(desc, priority);
+    else
+        gic_route_irq_to_xen(desc, priority);
+}
+
+bool_t platform_irq_is_routable(struct dt_raw_irq * rirq)
+{
+    /*
+     * If we have a platform-specific method to determine if an IRQ is 
routable,
+     * check that; otherwise fall back to checking to see if an IRQ belongs to
+     * the GIC.
+     */
+    if ( platform && platform->irq_is_routable )
+        return platform->irq_is_routable(rirq);
+    else
+        return (rirq->controller == dt_interrupt_controller);
+}
+
+int platform_irq_for_device(const struct dt_device_node *dev, int index)
+{
+    if ( platform && platform->irq_for_device )
+        return platform->irq_for_device(dev, index);
+    else
+        return platform_get_irq(dev, index);
+}
+
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index 7dae28b..e485b3b 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -162,7 +162,7 @@ static void __init init_dt_xen_time(void)
     /* Retrieve all IRQs for the timer */
     for ( i = TIMER_PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++ )
     {
-        res = platform_get_irq(timer, i);
+        res = platform_irq_for_device(timer, i);
 
         if ( res < 0 )
             panic("Timer: Unable to retrieve IRQ %u from the device tree", i);
diff --git a/xen/drivers/char/cadence-uart.c b/xen/drivers/char/cadence-uart.c
index 7f90f8d..be6ed10 100644
--- a/xen/drivers/char/cadence-uart.c
+++ b/xen/drivers/char/cadence-uart.c
@@ -29,6 +29,7 @@
 #include <xen/vmap.h>
 #include <asm/cadence-uart.h>
 #include <asm/io.h>
+#include <asm/platform.h>
 
 static struct cuart {
     unsigned int irq;
@@ -174,7 +175,7 @@ static int __init cuart_init(struct dt_device_node *dev, 
const void *data)
         return res;
     }
 
-    res = platform_get_irq(dev, 0);
+    res = platform_irq_for_device(dev, 0);
     if ( res < 0 )
     {
         printk("cadence: Unable to retrieve the IRQ\n");
diff --git a/xen/drivers/char/exynos4210-uart.c 
b/xen/drivers/char/exynos4210-uart.c
index bac1c2b..be90ffa 100644
--- a/xen/drivers/char/exynos4210-uart.c
+++ b/xen/drivers/char/exynos4210-uart.c
@@ -27,6 +27,7 @@
 #include <asm/device.h>
 #include <asm/exynos4210-uart.h>
 #include <asm/io.h>
+#include <asm/platform.h>
 
 static struct exynos4210_uart {
     unsigned int baud, clock_hz, data_bits, parity, stop_bits;
@@ -323,7 +324,7 @@ static int __init exynos4210_uart_init(struct 
dt_device_node *dev,
         return res;
     }
 
-    res = platform_get_irq(dev, 0);
+    res = platform_irq_for_device(dev, 0);
     if ( res < 0 )
     {
         printk("exynos4210: Unable to retrieve the IRQ\n");
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index bffdb35..d68d670 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -26,6 +26,7 @@
 #include <asm/io.h>
 #ifdef CONFIG_HAS_DEVICE_TREE
 #include <asm/device.h>
+#include <asm/platform.h>
 #endif
 #ifdef CONFIG_X86
 #include <asm/fixmap.h>
@@ -1279,7 +1280,7 @@ static int __init ns16550_uart_dt_init(struct 
dt_device_node *dev,
     if ( uart->reg_width != 1 && uart->reg_width != 4 )
         return -EINVAL;
 
-    res = platform_get_irq(dev, 0);
+    res = platform_irq_for_device(dev, 0);
     if ( ! res )
         return -EINVAL;
     uart->irq = res;
diff --git a/xen/drivers/char/omap-uart.c b/xen/drivers/char/omap-uart.c
index e96f6f5..1a7fe03 100644
--- a/xen/drivers/char/omap-uart.c
+++ b/xen/drivers/char/omap-uart.c
@@ -22,6 +22,7 @@
 #include <xen/vmap.h>
 #include <xen/8250-uart.h>
 #include <asm/io.h>
+#include <asm/platform.h>
 
 #define REG_SHIFT 2
 
@@ -353,7 +354,7 @@ static int __init omap_uart_init(struct dt_device_node *dev,
         return res;
     }
 
-    res = platform_get_irq(dev, 0);
+    res = platform_irq_for_device(dev, 0);
     if ( res < 0 )
     {
         printk("omap-uart: Unable to retrieve the IRQ\n");
diff --git a/xen/drivers/char/pl011.c b/xen/drivers/char/pl011.c
index 102f40d..b6c0fe1 100644
--- a/xen/drivers/char/pl011.c
+++ b/xen/drivers/char/pl011.c
@@ -29,6 +29,7 @@
 #include <xen/vmap.h>
 #include <asm/pl011-uart.h>
 #include <asm/io.h>
+#include <asm/platform.h>
 
 static struct pl011 {
     unsigned int data_bits, parity, stop_bits;
@@ -274,7 +275,7 @@ static int __init pl011_dt_uart_init(struct dt_device_node 
*dev,
         return res;
     }
 
-    res = platform_get_irq(dev, 0);
+    res = platform_irq_for_device(dev, 0);
     if ( res < 0 )
     {
         printk("pl011: Unable to retrieve the IRQ\n");
diff --git a/xen/drivers/char/scif-uart.c b/xen/drivers/char/scif-uart.c
index f9ae257..c3ab2bb 100644
--- a/xen/drivers/char/scif-uart.c
+++ b/xen/drivers/char/scif-uart.c
@@ -29,6 +29,7 @@
 #include <asm/device.h>
 #include <asm/scif-uart.h>
 #include <asm/io.h>
+#include <asm/platform.h>
 
 #define PARITY_NONE    0
 #define PARITY_EVEN    1
@@ -255,7 +256,7 @@ static int __init scif_uart_init(struct dt_device_node *dev,
         return res;
     }
 
-    res = platform_get_irq(dev, 0);
+    res = platform_irq_for_device(dev, 0);
     if ( res < 0 )
     {
         printk("scif-uart: Unable to retrieve the IRQ\n");
diff --git a/xen/drivers/passthrough/arm/smmu.c 
b/xen/drivers/passthrough/arm/smmu.c
index cf8b8b8..94d035a 100644
--- a/xen/drivers/passthrough/arm/smmu.c
+++ b/xen/drivers/passthrough/arm/smmu.c
@@ -103,7 +103,7 @@ static struct resource *platform_get_resource(struct 
platform_device *pdev,
                return ((ret) ? NULL : &res);
 
        case IORESOURCE_IRQ:
-               ret = platform_get_irq(pdev, num);
+               ret = platform_irq_for_device(pdev, num);
                if (ret < 0)
                        return NULL;
 
@@ -2349,7 +2349,7 @@ static int arm_smmu_device_dt_probe(struct 
platform_device *pdev)
        }
 
        for (i = 0; i < num_irqs; ++i) {
-               int irq = platform_get_irq(pdev, i);
+               int irq = platform_irq_for_device(pdev, i);
 
                if (irq < 0) {
                        dev_err(dev, "failed to get irq index %d\n", i);
diff --git a/xen/include/asm-arm/platform.h b/xen/include/asm-arm/platform.h
index f97315d..4ea278b 100644
--- a/xen/include/asm-arm/platform.h
+++ b/xen/include/asm-arm/platform.h
@@ -26,6 +26,13 @@ struct platform_desc {
     void (*reset)(void);
     /* Platform power-off */
     void (*poweroff)(void);
+    /* Platform-specific IRQ routing */
+    int (*route_irq_to_guest)(struct domain *d, unsigned int virq,
+                               struct irq_desc *desc, unsigned int priority);
+    void (*route_irq_to_xen)(struct irq_desc *desc, unsigned int priority);
+    bool_t (*irq_is_routable)(struct dt_raw_irq * rirq);
+    int (*irq_for_device)(const struct dt_device_node *dev, int index);
+
     /*
      * Platform blacklist devices
      * List of devices which must not pass-through to a guest
@@ -42,6 +49,13 @@ int platform_cpu_up(int cpu);
 #endif
 void platform_reset(void);
 void platform_poweroff(void);
+
+int platform_route_irq_to_guest(struct domain *d, unsigned int virq,
+                                 struct irq_desc *desc, unsigned int priority);
+void platform_route_irq_to_xen(struct irq_desc *desc, unsigned int priority);
+bool_t platform_irq_is_routable(struct dt_raw_irq *rirq);
+int platform_irq_for_device(const struct dt_device_node *dev, int index);
+
 bool_t platform_device_is_blacklisted(const struct dt_device_node *node);
 
 #define PLATFORM_START(_name, _namestr)                         \
-- 
2.9.2


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.