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>
This commit is contained in:
Cédric Le Goater
2017-04-26 12:00:42 +10:00
committed by David Gibson
parent bf5615e77c
commit 54f59d786c
6 changed files with 714 additions and 7 deletions
+1 -1
View File
@@ -6,7 +6,7 @@ obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o
obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o
# IBM PowerNV # IBM PowerNV
obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
obj-y += spapr_pci_vfio.o obj-y += spapr_pci_vfio.o
endif endif
+59 -6
View File
@@ -353,15 +353,22 @@ static void ppc_powernv_reset(void)
* have a CPLD that will collect the SerIRQ and shoot them as a * 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 * single level interrupt to the P8 chip. So let's setup a hook
* for doing just that. * 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) 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 PnvMachineState *pnv = POWERNV_MACHINE(qdev_get_machine());
* interrupt, so just drop interrupts on the floor 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) 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_initialize(&chip->lpc, sizeof(chip->lpc), TYPE_PNV_LPC);
object_property_add_child(obj, "lpc", OBJECT(&chip->lpc), NULL); 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) 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); error_propagate(errp, error);
return; 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[] = { static Property pnv_chip_properties[] = {
@@ -824,6 +846,29 @@ static const TypeInfo pnv_chip_info = {
.abstract = true, .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) static PowerPCCPU *ppc_get_vcpu_by_pir(int pir)
{ {
CPUState *cs; CPUState *cs;
@@ -850,6 +895,8 @@ static ICPState *pnv_icp_get(XICSFabric *xi, int pir)
static void pnv_pic_print_info(InterruptStatsProvider *obj, static void pnv_pic_print_info(InterruptStatsProvider *obj,
Monitor *mon) Monitor *mon)
{ {
PnvMachineState *pnv = POWERNV_MACHINE(obj);
int i;
CPUState *cs; CPUState *cs;
CPU_FOREACH(cs) { CPU_FOREACH(cs) {
@@ -857,6 +904,10 @@ static void pnv_pic_print_info(InterruptStatsProvider *obj,
icp_pic_print_info(ICP(cpu->intc), mon); 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, 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_boot_order = NULL;
mc->default_ram_size = 1 * G_BYTE; mc->default_ram_size = 1 * G_BYTE;
xic->icp_get = pnv_icp_get; 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; ispc->print_info = pnv_pic_print_info;
powernv_machine_class_props_init(oc); powernv_machine_class_props_init(oc);
+571
View File
File diff suppressed because it is too large Load Diff
+13
View File
@@ -22,6 +22,7 @@
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_lpc.h"
#include "hw/ppc/pnv_psi.h"
#define TYPE_PNV_CHIP "powernv-chip" #define TYPE_PNV_CHIP "powernv-chip"
#define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP) #define PNV_CHIP(obj) OBJECT_CHECK(PnvChip, (obj), TYPE_PNV_CHIP)
@@ -57,6 +58,7 @@ typedef struct PnvChip {
MemoryRegion icp_mmio; MemoryRegion icp_mmio;
PnvLpcController lpc; PnvLpcController lpc;
PnvPsi psi;
} PnvChip; } PnvChip;
typedef struct PnvChipClass { typedef struct PnvChipClass {
@@ -125,6 +127,7 @@ typedef struct PnvMachineState {
PnvChip **chips; PnvChip **chips;
ISABus *isa_bus; ISABus *isa_bus;
uint32_t cpld_irqstate;
} PnvMachineState; } PnvMachineState;
#define PNV_FDT_ADDR 0x01000000 #define PNV_FDT_ADDR 0x01000000
@@ -155,4 +158,14 @@ typedef struct PnvMachineState {
#define PNV_ICP_BASE(chip) \ #define PNV_ICP_BASE(chip) \
(0x0003ffff80000000ull + (uint64_t) PNV_CHIP_INDEX(chip) * PNV_ICP_SIZE) (0x0003ffff80000000ull + (uint64_t) PNV_CHIP_INDEX(chip) * PNV_ICP_SIZE)
#define PNV_PSIHB_SIZE 0x0000000000100000ull
#define PNV_PSIHB_BASE(chip) \
(0x0003fffe80000000ull + (uint64_t)PNV_CHIP_INDEX(chip) * PNV_PSIHB_SIZE)
#define PNV_PSIHB_FSP_SIZE 0x0000000100000000ull
#define PNV_PSIHB_FSP_BASE(chip) \
(0x0003ffe000000000ull + (uint64_t)PNV_CHIP_INDEX(chip) * \
PNV_PSIHB_FSP_SIZE)
#endif /* _PPC_PNV_H */ #endif /* _PPC_PNV_H */
+67
View File
@@ -0,0 +1,67 @@
/*
* QEMU PowerPC PowerNV Processor Service Interface (PSI) model
*
* Copyright (c) 2015-2017, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PPC_PNV_PSI_H
#define _PPC_PNV_PSI_H
#include "hw/sysbus.h"
#include "hw/ppc/xics.h"
#define TYPE_PNV_PSI "pnv-psi"
#define PNV_PSI(obj) \
OBJECT_CHECK(PnvPsi, (obj), TYPE_PNV_PSI)
#define PSIHB_XSCOM_MAX 0x20
typedef struct XICSState XICSState;
typedef struct PnvPsi {
SysBusDevice parent;
MemoryRegion regs_mr;
uint64_t bar;
/* FSP region not supported */
/* MemoryRegion fsp_mr; */
uint64_t fsp_bar;
/* Interrupt generation */
ICSState ics;
/* Registers */
uint64_t regs[PSIHB_XSCOM_MAX];
MemoryRegion xscom_regs;
} PnvPsi;
/* The PSI and FSP interrupts are muxed on the same IRQ number */
typedef enum PnvPsiIrq {
PSIHB_IRQ_PSI, /* internal use only */
PSIHB_IRQ_FSP, /* internal use only */
PSIHB_IRQ_OCC,
PSIHB_IRQ_FSI,
PSIHB_IRQ_LPC_I2C,
PSIHB_IRQ_LOCAL_ERR,
PSIHB_IRQ_EXTERNAL,
} PnvPsiIrq;
#define PSI_NUM_INTERRUPTS 6
extern void pnv_psi_irq_set(PnvPsi *psi, PnvPsiIrq irq, bool state);
#endif /* _PPC_PNV_PSI_H */
+3
View File
@@ -60,6 +60,9 @@ typedef struct PnvXScomInterfaceClass {
#define PNV_XSCOM_LPC_BASE 0xb0020 #define PNV_XSCOM_LPC_BASE 0xb0020
#define PNV_XSCOM_LPC_SIZE 0x4 #define PNV_XSCOM_LPC_SIZE 0x4
#define PNV_XSCOM_PSIHB_BASE 0x2010900
#define PNV_XSCOM_PSIHB_SIZE 0x20
extern void pnv_xscom_realize(PnvChip *chip, Error **errp); extern void pnv_xscom_realize(PnvChip *chip, Error **errp);
extern int pnv_xscom_populate(PnvChip *chip, void *fdt, int offset); extern int pnv_xscom_populate(PnvChip *chip, void *fdt, int offset);