aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/pnv.c
diff options
context:
space:
mode:
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);