diff options
author | Cédric Le Goater <clg@kaod.org> | 2017-04-05 14:41:26 +0200 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2017-04-26 12:00:42 +1000 |
commit | 54f59d786c05765bf7410eadd10e88f5579df9e7 (patch) | |
tree | 8a345cd8673055fb07ce8ad3aed2c288fde817f2 /hw/ppc/pnv.c | |
parent | bf5615e77cbe5518f201a9be96e13bedb6a5b26d (diff) |
ppc/pnv: Add cut down PSI bridge model and hookup external interrupt
The Processor Service Interface (PSI) Controller is one of the engines
of the "Bridge" unit which connects the different interfaces to the
Power Processor.
This adds just enough of the PSI bridge to handle various on-chip and
the one external interrupt. The rest of PSI has to do with the link to
the IBM FSP service processor which we don't plan to emulate (not used
on OpenPower machines).
The ics_get() and ics_resend() handlers of the XICSFabric interface of
the PowerNV machine are now defined to handle the Interrupt Control
Source of PSI. The InterruptStatsProvider interface is also modified
to dump the new ICS.
Originally from Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'hw/ppc/pnv.c')
-rw-r--r-- | hw/ppc/pnv.c | 65 |
1 files changed, 59 insertions, 6 deletions
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 1fa90d636b..a516acbe19 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -353,15 +353,22 @@ static void ppc_powernv_reset(void) * have a CPLD that will collect the SerIRQ and shoot them as a * single level interrupt to the P8 chip. So let's setup a hook * for doing just that. - * - * Note: The actual interrupt input isn't emulated yet, this will - * come with the PSI bridge model. */ static void pnv_lpc_isa_irq_handler_cpld(void *opaque, int n, int level) { - /* We don't yet emulate the PSI bridge which provides the external - * interrupt, so just drop interrupts on the floor - */ + PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine()); + uint32_t old_state = pnv->cpld_irqstate; + PnvChip *chip = opaque; + + if (level) { + pnv->cpld_irqstate |= 1u << n; + } else { + pnv->cpld_irqstate &= ~(1u << n); + } + if (pnv->cpld_irqstate != old_state) { + pnv_psi_irq_set(&chip->psi, PSIHB_IRQ_EXTERNAL, + pnv->cpld_irqstate != 0); + } } static void pnv_lpc_isa_irq_handler(void *opaque, int n, int level) @@ -682,6 +689,11 @@ static void pnv_chip_init(Object *obj) object_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC); object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL); + + object_initialize(&chip->psi, sizeof(chip->psi), TYPE_PNV_PSI); + object_property_add_child(obj, "psi", OBJECT(&chip->psi), NULL); + object_property_add_const_link(OBJECT(&chip->psi), "xics", + OBJECT(qdev_get_machine()), &error_abort); } static void pnv_chip_icp_realize(PnvChip *chip, Error **errp) @@ -794,6 +806,16 @@ static void pnv_chip_realize(DeviceState *dev, Error **errp) error_propagate(errp, error); return; } + + /* Processor Service Interface (PSI) Host Bridge */ + object_property_set_int(OBJECT(&chip->psi), PNV_PSIHB_BASE(chip), + "bar", &error_fatal); + object_property_set_bool(OBJECT(&chip->psi), true, "realized", &error); + if (error) { + error_propagate(errp, error); + return; + } + pnv_xscom_add_subregion(chip, PNV_XSCOM_PSIHB_BASE, &chip->psi.xscom_regs); } static Property pnv_chip_properties[] = { @@ -824,6 +846,29 @@ static const TypeInfo pnv_chip_info = { .abstract = true, }; +static ICSState *pnv_ics_get(XICSFabric *xi, int irq) +{ + PnvMachineState *pnv = POWERNV_MACHINE(xi); + int i; + + for (i = 0; i < pnv->num_chips; i++) { + if (ics_valid_irq(&pnv->chips[i]->psi.ics, irq)) { + return &pnv->chips[i]->psi.ics; + } + } + return NULL; +} + +static void pnv_ics_resend(XICSFabric *xi) +{ + PnvMachineState *pnv = POWERNV_MACHINE(xi); + int i; + + for (i = 0; i < pnv->num_chips; i++) { + ics_resend(&pnv->chips[i]->psi.ics); + } +} + static PowerPCCPU *ppc_get_vcpu_by_pir(int pir) { CPUState *cs; @@ -850,6 +895,8 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir) static void pnv_pic_print_info(InterruptStatsProvider *obj, Monitor *mon) { + PnvMachineState *pnv = POWERNV_MACHINE(obj); + int i; CPUState *cs; CPU_FOREACH(cs) { @@ -857,6 +904,10 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj, icp_pic_print_info(ICP(cpu->intc), mon); } + + for (i = 0; i < pnv->num_chips; i++) { + ics_pic_print_info(&pnv->chips[i]->psi.ics, mon); + } } static void pnv_get_num_chips(Object *obj, Visitor *v, const char *name, @@ -922,6 +973,8 @@ static void powernv_machine_class_init(ObjectClass *oc, void *data) mc->default_boot_order = NULL; mc->default_ram_size = 1 * G_BYTE; xic->icp_get = pnv_icp_get; + xic->ics_get = pnv_ics_get; + xic->ics_resend = pnv_ics_resend; ispc->print_info = pnv_pic_print_info; powernv_machine_class_props_init(oc); |