All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ian Campbell <ian.campbell@citrix.com>
To: xen-devel@lists.xen.org
Cc: Ian Campbell <ian.campbell@citrix.com>,
	stefano.stabellini@eu.citrix.com, julien.grall@linaro.org,
	tim@xen.org, Clark Laughlin <clark.laughlin@linaro.org>,
	Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
Subject: [PATCH 5/5] xen: arm: handle PCI DT node ranges and interrupt-map properties
Date: Fri, 24 Oct 2014 10:58:37 +0100	[thread overview]
Message-ID: <1414144717-32328-5-git-send-email-ian.campbell@citrix.com> (raw)
In-Reply-To: <1414144694.15687.31.camel@citrix.com>

These properties are defined in ePAPR and the OpenFirmware PCI Bus Binding
Specification (IEEE Std 1275-1994).

This replaces the xgene specific mapping. Tested on Mustang and on a model with
a PCI virtio controller.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
---
 xen/arch/arm/domain_build.c          |  193 ++++++++++++++++++++++++++++++++++
 xen/arch/arm/platforms/xgene-storm.c |   90 ----------------
 xen/include/xen/device_tree.h        |   32 ++++++
 3 files changed, 225 insertions(+), 90 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 998b6fd..00b5e07 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -907,6 +907,191 @@ static int make_timer_node(const struct domain *d, void *fdt,
     return res;
 }
 
+static int map_pci_device_ranges(struct domain *d,
+                                 const struct dt_device_node *dev,
+                                 const struct dt_pci_ranges_entry *ranges,
+                                 const u32 len)
+{
+    int i, nr, res;
+
+    if ( len % sizeof(struct dt_pci_ranges_entry) )
+    {
+        printk(XENLOG_ERR
+               "%s: ranges property length is not a multiple of entry size\n",
+               dt_node_name(dev));
+        return -EINVAL;
+    }
+
+    nr = len / sizeof(*ranges);
+
+    for ( i = 0; i < nr ; i++ )
+    {
+        const struct dt_pci_ranges_entry *range = &ranges[i];
+        u64 addr, len;
+
+        addr = fdt64_to_cpu(range->cpu_addr);
+        len = fdt64_to_cpu(range->length);
+
+        DPRINT("%s: ranges[%d]: 0x%08x.%08x.%08x 0x%"PRIx64" size 0x%"PRIx64"\n",
+               dt_node_name(dev), i,
+               fdt32_to_cpu(range->pci_addr.hi),
+               fdt32_to_cpu(range->pci_addr.mid),
+               fdt32_to_cpu(range->pci_addr.lo),
+               addr, len);
+
+        res = map_mmio_regions(d, paddr_to_pfn(addr & PAGE_MASK),
+                                  DIV_ROUND_UP(len, PAGE_SIZE),
+                                  paddr_to_pfn(addr & PAGE_MASK));
+        if ( res < 0 )
+        {
+            printk(XENLOG_ERR "%s: ranges[%d]: "
+                   "Unable to map 0x%"PRIx64" - 0x%"PRIx64" in domain %d\n",
+                   dt_node_name(dev), i,
+                   addr & PAGE_MASK, PAGE_ALIGN(addr + len) - 1,
+                   d->domain_id);
+            return res;
+        }
+    }
+    return 0;
+}
+
+static int map_device_ranges(struct domain *d, const struct dt_device_node *dev)
+{
+    const void *ranges;
+    u32 len;
+
+    if ( !dev->type )
+        return 0; /* No device type, nothing to do */
+
+    ranges = dt_get_property(dev, "ranges", &len);
+    if ( !ranges )
+        return 0; /* No ranges, nothing to do */
+
+    if ( dt_device_type_is_equal(dev, "pci") )
+        return map_pci_device_ranges(d, dev, ranges, len);
+    else if ( dt_device_type_is_equal(dev, "<NULL>") )
+        return 0; /* "<NULL>" is used for none */
+
+    DPRINT("Cannot handle ranges property for non-PCI device %s type %s\n",
+           dt_node_name(dev), dev->type);
+
+    /* Non-critical. */
+    return 0;
+}
+
+static int map_pci_device_interrupts(struct domain *d,
+                                     const struct dt_device_node *dev,
+                                     const __be32 *cells, const u32 len)
+{
+    const int intc_addr_cells =
+        dt_n_addr_cells_children(dt_interrupt_controller);
+    const size_t entry_size =
+        sizeof(struct dt_interrupt_map_entry) +
+        (intc_addr_cells + DT_NR_GIC_INTERRUPT_CELLS)*sizeof(__be32);
+
+    int i, nr, res;
+    u64 parent_addr;
+
+    if ( len % entry_size )
+    {
+        printk(XENLOG_ERR
+               "%s: interrupts property length is not a multiple of entry size %zd\n",
+               dt_node_name(dev), entry_size);
+        return -EINVAL;
+    }
+
+    nr = len / entry_size;
+
+    for ( i = 0; i < nr ; i++ )
+    {
+        const struct dt_interrupt_map_entry *map = (void *)cells;
+        struct dt_raw_irq dt_raw_irq;
+        struct dt_irq dt_irq;
+        int j;
+
+        if ( fdt32_to_cpu(map->phandle) != dt_interrupt_controller->phandle )
+        {
+            printk("%s: interrupt-map[%d]: Not connected to primary controller.\n",
+                   dt_node_name(dev), i);
+            continue;
+        }
+
+        dt_raw_irq.controller = dt_interrupt_controller;
+        dt_raw_irq.size = DT_NR_GIC_INTERRUPT_CELLS;
+
+        cells = &map->irq_specifier[0];
+
+        parent_addr = dt_next_cell(intc_addr_cells, &cells);
+        for (j = 0; j < DT_NR_GIC_INTERRUPT_CELLS; j++)
+            dt_raw_irq.specifier[j] = dt_next_cell(1, &cells);
+
+        res = dt_irq_translate(&dt_raw_irq, &dt_irq);
+        if ( res < 0 )
+        {
+            printk(XENLOG_ERR
+                   "%s: interrupt-map[%d]: Unable to translate raw IRQ\n",
+                   dt_node_name(dev), i);
+            continue;
+        }
+
+        DPRINT("%s: interrupt-map[%d]: 0x%"PRIx32".%"PRIx32".%"PRIx32" "
+               "pin=%"PRId32" phandle=%"PRIx32" "
+               "paddr=%"PRIx64" type=%"PRIx32" irq=%x\n",
+               dt_node_name(dev), i,
+               fdt32_to_cpu(map->pci_irq_mask.pci_addr.hi),
+               fdt32_to_cpu(map->pci_irq_mask.pci_addr.mid),
+               fdt32_to_cpu(map->pci_irq_mask.pci_addr.lo),
+               fdt32_to_cpu(map->pci_irq_mask.pci_pin),
+               fdt32_to_cpu(map->phandle),
+               parent_addr, dt_irq.type, dt_irq.irq);
+
+        /* Setup the IRQ type */
+        res = irq_set_type(dt_irq.irq, dt_irq.type);
+        if ( res )
+        {
+            printk(XENLOG_ERR
+                   "%s: interrupt-map[%d]: Unable to setup IRQ%"PRId32" to dom%d\n",
+                   dt_node_name(dev), i, dt_irq.irq, d->domain_id);
+            return res;
+        }
+
+        res = route_irq_to_guest(d, dt_irq.irq, dt_node_name(dev));
+        if ( res < 0 )
+        {
+            printk(XENLOG_ERR
+                   "%s: interrupt-map[%d]: Unable to map IRQ%"PRId32" to dom%d\n",
+                   dt_node_name(dev), i, dt_irq.irq, d->domain_id);
+            return res;
+        }
+    }
+    return 0;
+}
+
+static int map_device_interrupts(struct domain *d, const struct dt_device_node *dev)
+{
+    const void *map;
+    u32 len;
+
+    if ( !dev->type )
+        return 0; /* No device type, nothing to do */
+
+    map = dt_get_property(dev, "interrupt-map", &len);
+    if ( !map ) /* nothing to do */
+        return 0;
+
+    if ( dt_device_type_is_equal(dev, "pci") )
+        return map_pci_device_interrupts(d, dev, map, len);
+    else if ( dt_device_type_is_equal(dev, "<NULL>") )
+        return 0; /* "<NULL>" is used for none */
+
+    printk("Cannot handle interrupt-map for non-PCI device %s type %s\n",
+           dt_node_name(dev), dev->type);
+
+    /* Non-critical. */
+    return 0;
+}
+
+
 /* Map the device in the domain */
 static int map_device(struct domain *d, struct dt_device_node *dev)
 {
@@ -1015,6 +1200,14 @@ static int map_device(struct domain *d, struct dt_device_node *dev)
         }
     }
 
+    res = map_device_ranges(d, dev);
+    if ( res )
+        return res;
+
+    res = map_device_interrupts(d, dev);
+    if ( res )
+        return res;
+
     return 0;
 }
 
diff --git a/xen/arch/arm/platforms/xgene-storm.c b/xen/arch/arm/platforms/xgene-storm.c
index 29c4752..f88d306 100644
--- a/xen/arch/arm/platforms/xgene-storm.c
+++ b/xen/arch/arm/platforms/xgene-storm.c
@@ -40,95 +40,6 @@ static uint32_t xgene_storm_quirks(void)
     return PLATFORM_QUIRK_GIC_64K_STRIDE|PLATFORM_QUIRK_GUEST_PIRQ_NEED_EOI;
 }
 
-static int map_one_mmio(struct domain *d, const char *what,
-                         unsigned long start, unsigned long end)
-{
-    int ret;
-
-    printk("Additional MMIO %"PRIpaddr"-%"PRIpaddr" (%s)\n",
-           start, end, what);
-    ret = map_mmio_regions(d, start, end - start + 1, start);
-    if ( ret )
-        printk("Failed to map %s @ %"PRIpaddr" to dom%d\n",
-               what, start, d->domain_id);
-    return ret;
-}
-
-static int map_one_spi(struct domain *d, const char *what,
-                       unsigned int spi, unsigned int type)
-{
-    unsigned int irq;
-    int ret;
-
-    irq = spi + 32; /* SPIs start at IRQ 32 */
-
-    ret = irq_set_spi_type(irq, type);
-    if ( ret )
-    {
-        printk("Failed to set the type for IRQ%u\n", irq);
-        return ret;
-    }
-
-    printk("Additional IRQ %u (%s)\n", irq, what);
-
-    ret = route_irq_to_guest(d, irq, what);
-    if ( ret )
-        printk("Failed to route %s to dom%d\n", what, d->domain_id);
-
-    return ret;
-}
-
-/*
- * Xen does not currently support mapping MMIO regions and interrupt
- * for bus child devices (referenced via the "ranges" and
- * "interrupt-map" properties to domain 0). Instead for now map the
- * necessary resources manually.
- */
-static int xgene_storm_specific_mapping(struct domain *d)
-{
-    int ret;
-
-    /* Map the PCIe bus resources */
-    ret = map_one_mmio(d, "PCI MEM REGION", paddr_to_pfn(0xe000000000UL),
-                                            paddr_to_pfn(0xe010000000UL));
-    if ( ret )
-        goto err;
-
-    ret = map_one_mmio(d, "PCI IO REGION", paddr_to_pfn(0xe080000000UL),
-                                           paddr_to_pfn(0xe080010000UL));
-    if ( ret )
-        goto err;
-
-    ret = map_one_mmio(d, "PCI CFG REGION", paddr_to_pfn(0xe0d0000000UL),
-                                            paddr_to_pfn(0xe0d0200000UL));
-    if ( ret )
-        goto err;
-    ret = map_one_mmio(d, "PCI MSI REGION", paddr_to_pfn(0xe010000000UL),
-                                            paddr_to_pfn(0xe010800000UL));
-    if ( ret )
-        goto err;
-
-    ret = map_one_spi(d, "PCI#INTA", 0xc2, DT_IRQ_TYPE_LEVEL_HIGH);
-    if ( ret )
-        goto err;
-
-    ret = map_one_spi(d, "PCI#INTB", 0xc3, DT_IRQ_TYPE_LEVEL_HIGH);
-    if ( ret )
-        goto err;
-
-    ret = map_one_spi(d, "PCI#INTC", 0xc4, DT_IRQ_TYPE_LEVEL_HIGH);
-    if ( ret )
-        goto err;
-
-    ret = map_one_spi(d, "PCI#INTD", 0xc5, DT_IRQ_TYPE_LEVEL_HIGH);
-    if ( ret )
-        goto err;
-
-    ret = 0;
-err:
-    return ret;
-}
-
 static void xgene_storm_reset(void)
 {
     void __iomem *addr;
@@ -177,7 +88,6 @@ PLATFORM_START(xgene_storm, "APM X-GENE STORM")
     .init = xgene_storm_init,
     .reset = xgene_storm_reset,
     .quirks = xgene_storm_quirks,
-    .specific_mapping = xgene_storm_specific_mapping,
 
     .dom0_evtchn_ppi = 24,
     .dom0_gnttab_start = 0x1f800000,
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index ac2e876..d60ca94 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -682,6 +682,38 @@ int dt_parse_phandle_with_args(const struct dt_device_node *np,
                                const char *cells_name, int index,
                                struct dt_phandle_args *out_args);
 
+/*
+ * Definitions for implementing parts of the OpenFirmware PCI Bus Binding
+ * Specification (IEEE Std 1275-1994).
+ */
+
+struct dt_pci_unit_address {
+    __be32 hi, mid, lo;
+} __attribute__((packed));
+
+struct dt_pci_irq_mask {
+    struct dt_pci_unit_address    pci_addr;
+    __be32                        pci_pin;
+} __attribute__((packed));
+
+struct dt_pci_ranges_entry {
+    struct dt_pci_unit_address    pci_addr;
+    __be64                        cpu_addr;
+    __be64                        length;
+} __attribute__((packed));
+
+struct dt_interrupt_map_entry {
+    struct dt_pci_irq_mask             pci_irq_mask;
+    __be32                             phandle;
+    __be32			       irq_specifier[0];
+    /*
+     * irq_specifier is: parent-addr and interrupt-descriptor, both
+     * sized according to the interrupt-parent's #address-cells and
+     * #interrupt-cells.
+     */
+} __attribute__((packed));
+
+
 #endif /* __XEN_DEVICE_TREE_H */
 
 /*
-- 
1.7.10.4

  parent reply	other threads:[~2014-10-24  9:58 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-24  9:58 [PATCH for-4.6 0/5] xen: arm: Parse PCI DT nodes' ranges and interrupt-map Ian Campbell
2014-10-24  9:58 ` [PATCH 1/5] xen: arm: propagate gic's #address-cells property to dom0 Ian Campbell
2014-10-29 19:03   ` Julien Grall
2014-10-30 10:06     ` Ian Campbell
2014-10-30 10:31       ` Julien Grall
2014-11-04 10:23     ` Ian Campbell
2014-11-04 17:11       ` Konrad Rzeszutek Wilk
2014-11-05 10:47         ` Ian Campbell
2014-10-24  9:58 ` [PATCH 2/5] xen: device-tree: add accessors for the addr/size-cells of a node's children Ian Campbell
2014-10-24  9:58 ` [PATCH 3/5] xen: arm: Add DT_NR_GIC_INTERRUPT_CELLS rather than hardcoding 3 Ian Campbell
2014-10-24  9:58 ` [PATCH 4/5] xen: refactor irq_set_type out of platform_get_irq Ian Campbell
2014-10-24  9:58 ` Ian Campbell [this message]
2015-02-17 17:33   ` [PATCH 5/5] xen: arm: handle PCI DT node ranges and interrupt-map properties Julien Grall
2015-02-18 13:50     ` Ian Campbell
2015-02-18 14:19       ` Julien Grall
2015-02-18 14:37         ` Ian Campbell
2015-02-18 15:05           ` Julien Grall
2015-02-18 15:16             ` Julien Grall
2015-03-05 12:43               ` Ian Campbell
2015-03-05 15:59                 ` Julien Grall
2015-02-18 15:18             ` Ian Campbell
2015-02-18 15:31               ` Julien Grall
2015-02-18 15:44                 ` Ian Campbell
2015-02-18 15:13           ` Julien Grall
2015-02-18 15:21             ` Ian Campbell
2015-02-16  3:49 ` [PATCH for-4.6 0/5] xen: arm: Parse PCI DT nodes' ranges and interrupt-map Suravee Suthikulpanit
2015-02-16 10:12   ` Julien Grall
     [not found]     ` <54E2AFCC.3090302@amd.com>
2015-02-17 13:43       ` Julien Grall
2015-02-17 13:50         ` Andrew Cooper
2015-02-17 22:35           ` Suravee Suthikulanit
2015-02-18  0:31             ` Suravee Suthikulanit
2015-02-18  5:28               ` Suravee Suthikulanit
2015-02-18 12:48                 ` Julien Grall
2015-02-18 20:13                   ` Suravee Suthikulanit
2015-02-19  5:16                     ` Manish
2015-02-19  8:14                     ` Jan Beulich
2015-02-19  8:47                       ` Manish
2015-02-19 13:46                     ` Julien Grall
2015-02-18  7:58               ` Jan Beulich
2015-02-18 13:52   ` Ian Campbell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1414144717-32328-5-git-send-email-ian.campbell@citrix.com \
    --to=ian.campbell@citrix.com \
    --cc=clark.laughlin@linaro.org \
    --cc=julien.grall@linaro.org \
    --cc=pranavkumar@linaro.org \
    --cc=stefano.stabellini@eu.citrix.com \
    --cc=tim@xen.org \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.