diff --git a/xen/arch/arm/platforms/xgene-storm.c b/xen/arch/arm/platforms/xgene-storm.c index 1812e5ba18..c717360266 100644 --- a/xen/arch/arm/platforms/xgene-storm.c +++ b/xen/arch/arm/platforms/xgene-storm.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -35,9 +36,44 @@ static u64 reset_addr, reset_size; static u32 reset_mask; static bool reset_vals_valid = false; +#define XGENE_SEC_GICV2_DIST_ADDR 0x78010000 +static u32 __read_mostly xgene_quirks = PLATFORM_QUIRK_GIC_64K_STRIDE; + +static void __init xgene_check_pirq_eoi(void) +{ + const struct dt_device_node *node; + int res; + paddr_t dbase; + const struct dt_device_match xgene_dt_int_ctrl_match[] = + { + DT_MATCH_COMPATIBLE("arm,cortex-a15-gic"), + { /*sentinel*/ }, + }; + + node = dt_find_interrupt_controller(xgene_dt_int_ctrl_match); + if ( !node ) + panic("%s: Can not find interrupt controller node", __func__); + + res = dt_device_get_address(node, 0, &dbase, NULL); + if ( !dbase ) + panic("%s: Cannot find a valid address for the distributor", __func__); + + /* + * In old X-Gene Storm firmware and DT, secure mode addresses have + * been mentioned in GICv2 node. We have to use maintenance interrupt + * instead of EOI HW in this case. We check the GIC Distributor Base + * Address to maintain compatibility with older firmware. + */ + if ( dbase == XGENE_SEC_GICV2_DIST_ADDR ) + { + xgene_quirks |= PLATFORM_QUIRK_GUEST_PIRQ_NEED_EOI; + printk("Xen: WARNING: OLD X-Gene Firmware, disabling PIRQ EOI mode\n"); + } +} + static uint32_t xgene_storm_quirks(void) { - return PLATFORM_QUIRK_GIC_64K_STRIDE|PLATFORM_QUIRK_GUEST_PIRQ_NEED_EOI; + return xgene_quirks; } static int map_one_mmio(struct domain *d, const char *what, @@ -216,6 +252,8 @@ static int xgene_storm_init(void) reset_mask = XGENE_RESET_MASK; reset_vals_valid = true; + xgene_check_pirq_eoi(); + return 0; }