From: Ian Campbell <ian.campbell@citrix.com>
To: xen-devel@lists.xen.org
Cc: julien.grall@citrix.com, Ian Campbell <ian.campbell@citrix.com>,
stefano.stabellini@eu.citrix.com
Subject: [PATCH v6 4/6] xen: arm: map child MMIO and IRQs to dom0 for PCI bus DT nodes.
Date: Fri, 3 Jul 2015 16:56:10 +0100 [thread overview]
Message-ID: <1435938972-18288-4-git-send-email-ian.campbell@citrix.com> (raw)
In-Reply-To: <1435938959.9447.171.camel@citrix.com>
This uses the dt_for_each_{irq_map,range} helpers to map the interrupt
and child MMIO regions to dom0. Since PCI busses are enumerable these
resources may not be otherwise described in the DT (although they can
be).
Although PCI is the only bus we handle this way the code should be
generic enough to apply to similar buses in the future.
This replaces the xgene specific mapping. Tested on Mustang and on a
model with a PCI virtio controller.
This patch doesn't stop recursing when it finds such a node, since
double mapping these resources if they do happen to be described is
(or should be) harmless
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
---
v2: This is essentially a complete reworking, which actually parses
things properly (obeying #{address,size,interrupt}-cells on the
appriopriate nodes) and includes handling of interrupt-map too.
v3: Use dt_for_each_ranges and refactor handling into
handle_device_children.
Retitled from "xen: arm: handle PCI DT node ranges and
interrupt-map properties" and rewrote much of the commit message.
This change also essentially obsoleted any discussion about
logging unhandled buses since it no longer makes sense (or at
least there is nothing convenient to hang it off)
v4: dt_for_each_irq_map now provides the translated IRQ, so adjust
accordingly.
Call irq_permit_access to allow dom0 to passthrough the device to
another domain.
Only call route_irq_to_guest, map_mmio_regions and (newly added
call to) vgic_reserve_virq if the device is not marked as reserved
for passthrough.
v5: Call iomem_permit_access too
---
xen/arch/arm/domain_build.c | 127 ++++++++++++++++++++++++++++++
xen/arch/arm/platforms/xgene-storm.c | 143 ----------------------------------
2 files changed, 127 insertions(+), 143 deletions(-)
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 980a2a3..22b4c04 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -954,6 +954,129 @@ static int make_timer_node(const struct domain *d, void *fdt,
return res;
}
+static int map_interrupt_to_domain(const struct dt_device_node *dev,
+ const struct dt_irq *dt_irq,
+ void *data)
+{
+ struct domain *d = data;
+ bool_t need_mapping = !dt_device_for_passthrough(dev);
+ unsigned int irq = dt_irq->irq;
+ int res;
+
+ if ( irq < NR_LOCAL_IRQS )
+ {
+ printk(XENLOG_ERR "%s: IRQ%"PRId32" is not a SPI\n",
+ dt_node_name(dev), irq);
+ return -EINVAL;
+ }
+
+ /* Setup the IRQ type */
+ res = irq_set_spi_type(irq, dt_irq->type);
+ if ( res )
+ {
+ printk(XENLOG_ERR
+ "%s: Unable to setup IRQ%"PRId32" to dom%d\n",
+ dt_node_name(dev), irq, d->domain_id);
+ return res;
+ }
+
+ res = irq_permit_access(d, irq);
+ if ( res )
+ {
+ printk(XENLOG_ERR "Unable to permit to dom%u access to IRQ %u\n",
+ d->domain_id, irq);
+ return res;
+ }
+
+ if ( need_mapping )
+ {
+ /*
+ * Checking the return of vgic_reserve_virq is not
+ * necessary. It should not fail except when we try to map
+ * the IRQ twice. This can legitimately happen if the IRQ is shared
+ */
+ vgic_reserve_virq(d, irq);
+
+ res = route_irq_to_guest(d, irq, irq, dt_node_name(dev));
+ if ( res < 0 )
+ {
+ printk(XENLOG_ERR "Unable to map IRQ%"PRId32" to dom%d\n",
+ irq, d->domain_id);
+ return res;
+ }
+ }
+
+ DPRINT(" - IRQ: %u\n", irq);
+
+ return 0;
+}
+
+static int map_range_to_domain(const struct dt_device_node *dev,
+ u64 addr, u64 len,
+ void *data)
+{
+ struct domain *d = data;
+ bool_t need_mapping = !dt_device_for_passthrough(dev);
+ int res;
+
+ res = iomem_permit_access(d, paddr_to_pfn(addr & PAGE_MASK),
+ paddr_to_pfn(PAGE_ALIGN(addr + len - 1)));
+ if ( res )
+ {
+ printk(XENLOG_ERR "Unable to permit to dom%d access to"
+ " 0x%"PRIx64" - 0x%"PRIx64"\n",
+ d->domain_id,
+ addr & PAGE_MASK, PAGE_ALIGN(addr + len) - 1);
+ return res;
+ }
+
+ if ( need_mapping )
+ {
+ 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 "Unable to map 0x%"PRIx64
+ " - 0x%"PRIx64" in domain %d\n",
+ addr & PAGE_MASK, PAGE_ALIGN(addr + len) - 1,
+ d->domain_id);
+ return res;
+ }
+ }
+
+ DPRINT(" - MMIO: %010"PRIx64" - %010"PRIx64"\n", addr, addr + len);
+
+ return 0;
+}
+
+/*
+ * For a node which describes a discoverable bus (such as a PCI bus)
+ * then we may need to perform additional mappings in order to make
+ * the child resources available to domain 0.
+ */
+static int map_device_children(struct domain *d,
+ const struct dt_device_node *dev)
+{
+ int ret;
+
+ if ( dt_device_type_is_equal(dev, "pci") )
+ {
+ DPRINT("Mapping children of %s to guest\n", dt_node_full_name(dev));
+
+ ret = dt_for_each_irq_map(dev, &map_interrupt_to_domain, d);
+ if ( ret < 0 )
+ return ret;
+
+ ret = dt_for_each_range(dev, &map_range_to_domain, d);
+ if ( ret < 0 )
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* For a given device node:
* - Give permission to the guest to manage IRQ and MMIO range
@@ -1093,6 +1216,10 @@ static int handle_device(struct domain *d, struct dt_device_node *dev)
}
}
+ res = map_device_children(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 26754b5..8b05ed5 100644
--- a/xen/arch/arm/platforms/xgene-storm.c
+++ b/xen/arch/arm/platforms/xgene-storm.c
@@ -73,148 +73,6 @@ static uint32_t xgene_storm_quirks(void)
return PLATFORM_QUIRK_GIC_64K_STRIDE;
}
-static int map_one_mmio(struct domain *d, const char *what,
- unsigned long start, unsigned long end)
-{
- int ret;
-
- printk("Additional MMIO %lx-%lx (%s)\n",
- start, end, what);
- ret = map_mmio_regions(d, start, end - start, start);
- if ( ret )
- printk("Failed to map %s @ %lx 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);
-
- if ( !vgic_reserve_virq(d, irq) )
- printk("Failed to reserve vIRQ %u on dom%d\n",
- irq, d->domain_id);
-
- ret = route_irq_to_guest(d, irq, irq, what);
- if ( ret )
- printk("Failed to route %s to dom%d\n", what, d->domain_id);
-
- return ret;
-}
-
-/* Creates MMIO mappings base..end as well as 4 SPIs from the given base. */
-static int xgene_storm_pcie_specific_mapping(struct domain *d,
- const struct dt_device_node *node,
- paddr_t base, paddr_t end,
- int base_spi)
-{
- int ret;
-
- printk("Mapping additional regions for PCIe device %s\n",
- dt_node_full_name(node));
-
- /* Map the PCIe bus resources */
- ret = map_one_mmio(d, "PCI MEMORY", paddr_to_pfn(base), paddr_to_pfn(end));
- if ( ret )
- goto err;
-
- ret = map_one_spi(d, "PCI#INTA", base_spi+0, DT_IRQ_TYPE_LEVEL_HIGH);
- if ( ret )
- goto err;
-
- ret = map_one_spi(d, "PCI#INTB", base_spi+1, DT_IRQ_TYPE_LEVEL_HIGH);
- if ( ret )
- goto err;
-
- ret = map_one_spi(d, "PCI#INTC", base_spi+2, DT_IRQ_TYPE_LEVEL_HIGH);
- if ( ret )
- goto err;
-
- ret = map_one_spi(d, "PCI#INTD", base_spi+3, DT_IRQ_TYPE_LEVEL_HIGH);
- if ( ret )
- goto err;
-
- ret = 0;
-err:
- 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)
-{
- struct dt_device_node *node = NULL;
- int ret;
-
- while ( (node = dt_find_compatible_node(node, "pci", "apm,xgene-pcie")) )
- {
- u64 addr;
-
- /* Identify the bus via it's control register address */
- ret = dt_device_get_address(node, 0, &addr, NULL);
- if ( ret < 0 )
- return ret;
-
- if ( !dt_device_is_available(node) )
- continue;
-
- switch ( addr )
- {
- case 0x1f2b0000: /* PCIe0 */
- ret = xgene_storm_pcie_specific_mapping(d,
- node,
- 0x0e000000000UL, 0x10000000000UL, 0xc2);
- break;
- case 0x1f2c0000: /* PCIe1 */
- ret = xgene_storm_pcie_specific_mapping(d,
- node,
- 0x0d000000000UL, 0x0e000000000UL, 0xc8);
- break;
- case 0x1f2d0000: /* PCIe2 */
- ret = xgene_storm_pcie_specific_mapping(d,
- node,
- 0x09000000000UL, 0x0a000000000UL, 0xce);
- break;
- case 0x1f500000: /* PCIe3 */
- ret = xgene_storm_pcie_specific_mapping(d,
- node,
- 0x0a000000000UL, 0x0c000000000UL, 0xd4);
- break;
- case 0x1f510000: /* PCIe4 */
- ret = xgene_storm_pcie_specific_mapping(d,
- node,
- 0x0c000000000UL, 0x0d000000000UL, 0xda);
- break;
-
- default:
- printk("Ignoring unknown PCI bus %s\n", dt_node_full_name(node));
- continue;
- }
-
- if ( ret < 0 )
- return ret;
- }
-
- return 0;
-}
-
static void xgene_storm_reset(void)
{
void __iomem *addr;
@@ -265,7 +123,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,
PLATFORM_END
/*
--
1.7.10.4
next prev parent reply other threads:[~2015-07-03 15:56 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-07-03 15:55 [PATCH v6 0/6] xen: arm: Parse PCI DT nodes' ranges and interrupt-map Ian Campbell
2015-07-03 15:56 ` [PATCH v6 1/6] xen: dt: add dt_for_each_irq_map helper Ian Campbell
2015-07-03 15:56 ` [PATCH v6 2/6] xen: dt: add dt_for_each_range helper Ian Campbell
2015-07-03 15:56 ` [PATCH v6 3/6] xen: arm: drop redundant extra call to vgic_reserve_virq Ian Campbell
2015-07-03 15:56 ` Ian Campbell [this message]
2015-07-06 10:58 ` [PATCH v6 4/6] xen: arm: map child MMIO and IRQs to dom0 for PCI bus DT nodes Julien Grall
2015-07-03 15:56 ` [PATCH v6 5/6] xen: arm: Import of_bus PCI entry from Linux (as a dt_bus entry) Ian Campbell
2015-07-06 10:59 ` Julien Grall
2015-07-03 15:56 ` [PATCH v6 6/6] xen: arm: consolidate mmio and irq mapping to dom0 Ian Campbell
2015-07-06 11:02 ` Julien Grall
2015-07-06 11:04 ` [PATCH v6 0/6] xen: arm: Parse PCI DT nodes' ranges and interrupt-map Julien Grall
2015-07-06 13:56 ` 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=1435938972-18288-4-git-send-email-ian.campbell@citrix.com \
--to=ian.campbell@citrix.com \
--cc=julien.grall@citrix.com \
--cc=stefano.stabellini@eu.citrix.com \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).