aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/pnv.c
diff options
context:
space:
mode:
authorCédric Le Goater <clg@kaod.org>2017-04-05 14:41:26 +0200
committerDavid Gibson <david@gibson.dropbear.id.au>2017-04-26 12:00:42 +1000
commit54f59d786c05765bf7410eadd10e88f5579df9e7 (patch)
tree8a345cd8673055fb07ce8ad3aed2c288fde817f2 /hw/ppc/pnv.c
parentbf5615e77cbe5518f201a9be96e13bedb6a5b26d (diff)
downloadqemu-54f59d786c05765bf7410eadd10e88f5579df9e7.zip
qemu-54f59d786c05765bf7410eadd10e88f5579df9e7.tar.gz
qemu-54f59d786c05765bf7410eadd10e88f5579df9e7.tar.bz2
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.c65
1 files changed, 59 insertions, 6 deletions
diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c
index 1fa90d6..a516acb 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);