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),
+ 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),
+ DIV_ROUND_UP(len, PAGE_SIZE),
+ paddr_to_pfn(addr));
+ 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
}
}
+ res = map_device_children(d, dev);
+ if ( res )
+ return res;
+
return 0;
}
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;
.init = xgene_storm_init,
.reset = xgene_storm_reset,
.quirks = xgene_storm_quirks,
- .specific_mapping = xgene_storm_specific_mapping,
PLATFORM_END
/*