diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/phb4.c | 47 | ||||
-rw-r--r-- | hw/xive2.c | 40 |
2 files changed, 77 insertions, 10 deletions
@@ -136,8 +136,6 @@ static void phb4_init_hw(struct phb4 *p); #define PHBLOGCFG(p, fmt, a...) do {} while (0) #endif -#define PHB4_CAN_STORE_EOI(p) XIVE_STORE_EOI_ENABLED - static bool pci_eeh_mmio; static bool pci_retry_all; static int rx_err_max = PHB4_RX_ERR_MAX; @@ -152,6 +150,24 @@ static inline bool is_phb5(void) return (proc_gen == proc_gen_p10); } +/* PQ offloading on the XIVE IC. */ +static inline bool phb_pq_disable(struct phb4 *p __unused) +{ + if (is_phb5()) + return 1; + + return false; +} + +static inline bool phb_can_store_eoi(struct phb4 *p) +{ + if (is_phb5()) + /* PQ offloading is required for StoreEOI */ + return XIVE2_STORE_EOI_ENABLED && phb_pq_disable(p); + + return XIVE_STORE_EOI_ENABLED; +} + /* Note: The "ASB" name is historical, practically this means access via * the XSCOM backdoor */ @@ -5366,8 +5382,12 @@ static void phb4_init_hw(struct phb4 *p) val = PHB_CTRLR_IRQ_PGSZ_64K; val |= PHB_CTRLR_TCE_CLB_DISABLE; // HW557787 circumvention val |= SETFIELD(PHB_CTRLR_TVT_ADDR_SEL, 0ull, TVT_2_PER_PE); - if (PHB4_CAN_STORE_EOI(p)) + if (phb_pq_disable(p)) + val |= PHB_CTRLR_IRQ_PQ_DISABLE; + if (phb_can_store_eoi(p)) { val |= PHB_CTRLR_IRQ_STORE_EOI; + PHBDBG(p, "store EOI is enabled\n"); + } if (!pci_eeh_mmio) val |= PHB_CTRLR_MMIO_EEH_DISABLE; @@ -5927,16 +5947,29 @@ static void phb4_create(struct dt_node *np) /* Compute XIVE source flags depending on PHB revision */ irq_flags = 0; - if (PHB4_CAN_STORE_EOI(p)) + if (phb_can_store_eoi(p)) irq_flags |= XIVE_SRC_STORE_EOI; else irq_flags |= XIVE_SRC_TRIGGER_PAGE; if (is_phb5()) { - /* Register all interrupt sources with XIVE */ - xive2_register_hw_source(p->base_msi, p->num_irqs - 8, 16, - p->int_mmio, irq_flags, NULL, NULL); + /* + * Register sources with XIVE. If offloading is on, use the + * ESB pages of the XIVE IC for the MSI sources instead of the + * ESB pages of the PHB. + */ + if (phb_pq_disable(p)) { + xive2_register_esb_source(p->base_msi, p->num_irqs - 8); + } else { + xive2_register_hw_source(p->base_msi, + p->num_irqs - 8, 16, + p->int_mmio, irq_flags, + NULL, NULL); + } + /* + * LSI sources always use the ESB pages of the PHB. + */ xive2_register_hw_source(p->base_lsi, 8, 16, p->int_mmio + ((p->num_irqs - 8) << 16), XIVE_SRC_LSI, p, &phb4_lsi_ops); @@ -2578,8 +2578,8 @@ void xive2_register_hw_source(uint32_t base, uint32_t count, uint32_t shift, false, data, ops); } -void xive2_register_ipi_source(uint32_t base, uint32_t count, void *data, - const struct irq_source_ops *ops) +static void __xive2_register_esb_source(uint32_t base, uint32_t count, + void *data, const struct irq_source_ops *ops) { struct xive_src *s; struct xive *x = xive_from_isn(base); @@ -2588,7 +2588,6 @@ void xive2_register_ipi_source(uint32_t base, uint32_t count, void *data, uint32_t flags = XIVE_SRC_EOI_PAGE1 | XIVE_SRC_TRIGGER_PAGE; assert(x); - assert(base >= x->int_base && (base + count) <= x->int_ipi_top); s = malloc(sizeof(struct xive_src)); assert(s); @@ -2604,6 +2603,41 @@ void xive2_register_ipi_source(uint32_t base, uint32_t count, void *data, flags, false, data, ops); } +/* + * Check that IPI sources have interrupt numbers in the IPI interrupt + * number range + */ +void xive2_register_ipi_source(uint32_t base, uint32_t count, void *data, + const struct irq_source_ops *ops) +{ + struct xive *x = xive_from_isn(base); + + assert(x); + assert(base >= x->int_base && (base + count) <= x->int_ipi_top); + + __xive2_register_esb_source(base, count, data, ops); +} + +/* + * Some HW sources (PHB) can disable the use of their own ESB pages + * and offload all the checks on ESB pages of the IC. The interrupt + * numbers are not necessarily in the IPI range. + */ +void xive2_register_esb_source(uint32_t base, uint32_t count) +{ + __xive2_register_esb_source(base, count, NULL, NULL); +} + +uint64_t xive2_get_esb_base(uint32_t base) +{ + struct xive *x = xive_from_isn(base); + uint32_t base_idx = GIRQ_TO_IDX(base); + + assert(x); + + return (uint64_t) x->esb_base + (1ul << XIVE_ESB_SHIFT) * base_idx; +} + static void xive_set_quirks(struct xive *x, struct proc_chip *chip __unused) { uint64_t quirks = 0; |