[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 5/6] xen: arm: map child MMIO and IRQs to dom0 for PCI bus DT nodes.
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@xxxxxxxxxx> --- 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. --- xen/arch/arm/domain_build.c | 121 ++++++++++++++++++++++++++++ xen/arch/arm/platforms/xgene-storm.c | 143 ---------------------------------- 2 files changed, 121 insertions(+), 143 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 1242c88..d65c849 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -935,6 +935,123 @@ 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; + int res; + + 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) +{ + bool_t need_mapping = !dt_device_for_passthrough(dev); + int ret; + + if ( dt_device_type_is_equal(dev, "pci") ) + { + DPRINT("Mapping children of %s to guest\n", dt_node_full_name(dev)); + + /* + * We need to handle IRQs even if !need_mapping in order to + * setup the domain's permissions on the device's IRQs, such + * that it can pass them through to other domains. + */ + ret = dt_for_each_irq_map(dev, &map_interrupt_to_domain, d); + if ( ret < 0 ) + return ret; + + if ( need_mapping ) + { + 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 @@ -1074,6 +1191,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 c717360..065b3e1 100644 --- a/xen/arch/arm/platforms/xgene-storm.c +++ b/xen/arch/arm/platforms/xgene-storm.c @@ -76,148 +76,6 @@ static uint32_t xgene_storm_quirks(void) return xgene_quirks; } -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; @@ -268,7 +126,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_gnttab_start = 0x1f800000, .dom0_gnttab_size = 0x20000, -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |