Add support for the XIVE XICS emulation mode for POWER9 systems
Summary: POWER9 systems use a new interrupt controller, XIVE, managed through OPAL firmware calls. The OPAL firmware includes support for emulating the previous generation XICS presentation layer in addition to a new "XIVE Exploitation" mode. As a stopgap until we have XIVE exploitation mode, enable XICS emulation mode so that we at least have an interrupt controller. Since the CPPR is local to the current CPU, it cannot be updated for APs when initializing on the BSP. This adds a new function, directly called by the powernv platform code, to initialize the CPPR on AP bringup. Reviewed by: nwhitehorn Differential Revision: https://reviews.freebsd.org/D15492
This commit is contained in:
parent
056b40e29c
commit
ef6da5e5c7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=333912
@ -96,7 +96,7 @@ cpudep_ap_early_bootstrap(void)
|
||||
mtspr(SPR_LPID, 0);
|
||||
isync();
|
||||
|
||||
mtspr(SPR_LPCR, LPCR_LPES);
|
||||
mtspr(SPR_LPCR, lpcr);
|
||||
isync();
|
||||
}
|
||||
#endif
|
||||
@ -401,7 +401,7 @@ cpudep_ap_setup()
|
||||
case IBMPOWER9:
|
||||
#ifdef __powerpc64__
|
||||
if (mfmsr() & PSL_HV) {
|
||||
mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_LPES |
|
||||
mtspr(SPR_LPCR, mfspr(SPR_LPCR) | lpcr |
|
||||
LPCR_PECE_WAKESET);
|
||||
isync();
|
||||
}
|
||||
|
@ -135,6 +135,7 @@ extern char etext[];
|
||||
#ifdef __powerpc64__
|
||||
extern void enter_idle_powerx(void);
|
||||
extern uint64_t can_wakeup;
|
||||
extern register_t lpcr;
|
||||
#endif
|
||||
|
||||
void cpu_halt(void);
|
||||
|
@ -215,14 +215,6 @@
|
||||
#define FSL_E300C3 0x8085
|
||||
#define FSL_E300C4 0x8086
|
||||
|
||||
#define SPR_LPCR 0x13e /* Logical Partitioning Control */
|
||||
#define LPCR_LPES 0x008 /* Bit 60 */
|
||||
#define LPCR_PECE_DRBL (1ULL << 16) /* Directed Privileged Doorbell */
|
||||
#define LPCR_PECE_HDRBL (1ULL << 15) /* Directed Hypervisor Doorbell */
|
||||
#define LPCR_PECE_EXT (1ULL << 14) /* External exceptions */
|
||||
#define LPCR_PECE_DECR (1ULL << 13) /* Decrementer exceptions */
|
||||
#define LPCR_PECE_ME (1ULL << 12) /* Machine Check and Hypervisor */
|
||||
/* Maintenance exceptions */
|
||||
#define LPCR_PECE_WAKESET (LPCR_PECE_EXT | LPCR_PECE_DECR | LPCR_PECE_ME)
|
||||
|
||||
#define SPR_EPCR 0x133
|
||||
@ -242,7 +234,14 @@
|
||||
#define SPR_HSRR0 0x13a
|
||||
#define SPR_HSRR1 0x13b
|
||||
#define SPR_LPCR 0x13e /* Logical Partitioning Control */
|
||||
#define LPCR_LPES 0x008 /* Bit 60 */
|
||||
#define LPCR_LPES 0x008 /* Bit 60 */
|
||||
#define LPCR_HVICE 0x002 /* Hypervisor Virtualization Interrupt (Arch 3.0) */
|
||||
#define LPCR_PECE_DRBL (1ULL << 16) /* Directed Privileged Doorbell */
|
||||
#define LPCR_PECE_HDRBL (1ULL << 15) /* Directed Hypervisor Doorbell */
|
||||
#define LPCR_PECE_EXT (1ULL << 14) /* External exceptions */
|
||||
#define LPCR_PECE_DECR (1ULL << 13) /* Decrementer exceptions */
|
||||
#define LPCR_PECE_ME (1ULL << 12) /* Machine Check and Hypervisor */
|
||||
/* Maintenance exceptions */
|
||||
#define SPR_LPID 0x13f /* Logical Partitioning Control */
|
||||
|
||||
#define SPR_PTCR 0x1d0 /* Partition Table Control Register */
|
||||
|
@ -73,7 +73,12 @@ int opal_call(uint64_t token, ...);
|
||||
#define OPAL_REINIT_CPUS 70
|
||||
#define OPAL_CHECK_ASYNC_COMPLETION 86
|
||||
#define OPAL_I2C_REQUEST 109
|
||||
#define OPAL_INT_GET_XIRR 122
|
||||
#define OPAL_INT_SET_CPPR 123
|
||||
#define OPAL_INT_EOI 124
|
||||
#define OPAL_INT_SET_MFRR 125
|
||||
#define OPAL_PCI_TCE_KILL 126
|
||||
#define OPAL_XIVE_RESET 128
|
||||
|
||||
/* For OPAL_PCI_SET_PE */
|
||||
#define OPAL_UNMAP_PE 0
|
||||
|
@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
|
||||
extern void *ap_pcpu;
|
||||
#endif
|
||||
|
||||
extern void xicp_smp_cpu_startup(void);
|
||||
static int powernv_probe(platform_t);
|
||||
static int powernv_attach(platform_t);
|
||||
void powernv_mem_regions(platform_t, struct mem_region *phys, int *physsz,
|
||||
@ -152,14 +153,14 @@ powernv_attach(platform_t plat)
|
||||
mtspr(SPR_LPID, 0);
|
||||
isync();
|
||||
|
||||
mtspr(SPR_LPCR, LPCR_LPES);
|
||||
if (cpu_features2 & PPC_FEATURE2_ARCH_3_00)
|
||||
lpcr |= LPCR_HVICE;
|
||||
|
||||
mtspr(SPR_LPCR, lpcr);
|
||||
isync();
|
||||
|
||||
mtmsr(msr);
|
||||
|
||||
/* Init CPU bits */
|
||||
powernv_smp_ap_init(plat);
|
||||
|
||||
powernv_cpuref_init();
|
||||
|
||||
/* Set SLB count from device tree */
|
||||
@ -460,6 +461,8 @@ powernv_reset(platform_t platform)
|
||||
static void
|
||||
powernv_smp_ap_init(platform_t platform)
|
||||
{
|
||||
|
||||
xicp_smp_cpu_startup();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -240,6 +240,10 @@ SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLFLAG_RD,
|
||||
SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features2, CTLFLAG_RD,
|
||||
&cpu_features2, sizeof(cpu_features2), "LX", "PowerPC CPU features 2");
|
||||
|
||||
#ifdef __powerpc64__
|
||||
register_t lpcr = LPCR_LPES;
|
||||
#endif
|
||||
|
||||
/* Provide some user-friendly aliases for bits in cpu_features */
|
||||
SYSCTL_PROC(_hw, OID_AUTO, floatingpoint, CTLTYPE_INT | CTLFLAG_RD,
|
||||
0, PPC_FEATURE_HAS_FPU, cpu_feature_bit, "I",
|
||||
|
@ -61,6 +61,9 @@ __FBSDID("$FreeBSD$");
|
||||
#define XICP_IPI 2
|
||||
#define MAX_XICP_IRQS (1<<24) /* 24-bit XIRR field */
|
||||
|
||||
#define XIVE_XICS_MODE_EMU 0
|
||||
#define XIVE_XICS_MODE_EXP 1
|
||||
|
||||
static int xicp_probe(device_t);
|
||||
static int xicp_attach(device_t);
|
||||
static int xics_probe(device_t);
|
||||
@ -74,6 +77,10 @@ static void xicp_ipi(device_t, u_int);
|
||||
static void xicp_mask(device_t, u_int);
|
||||
static void xicp_unmask(device_t, u_int);
|
||||
|
||||
#ifdef POWERNV
|
||||
void xicp_smp_cpu_startup(void);
|
||||
#endif
|
||||
|
||||
static device_method_t xicp_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, xicp_probe),
|
||||
@ -117,6 +124,7 @@ struct xicp_softc {
|
||||
int cpu;
|
||||
} intvecs[256];
|
||||
int nintvecs;
|
||||
bool xics_emu;
|
||||
};
|
||||
|
||||
static driver_t xicp_driver = {
|
||||
@ -131,6 +139,8 @@ static driver_t xics_driver = {
|
||||
0
|
||||
};
|
||||
|
||||
static uint32_t cpu_xirr[MAXCPU];
|
||||
|
||||
static devclass_t xicp_devclass;
|
||||
static devclass_t xics_devclass;
|
||||
|
||||
@ -161,7 +171,8 @@ static int
|
||||
xicp_probe(device_t dev)
|
||||
{
|
||||
|
||||
if (!ofw_bus_is_compatible(dev, "ibm,ppc-xicp"))
|
||||
if (!ofw_bus_is_compatible(dev, "ibm,ppc-xicp") &&
|
||||
!ofw_bus_is_compatible(dev, "ibm,opal-intc"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "External Interrupt Presentation Controller");
|
||||
@ -172,7 +183,8 @@ static int
|
||||
xics_probe(device_t dev)
|
||||
{
|
||||
|
||||
if (!ofw_bus_is_compatible(dev, "ibm,ppc-xics"))
|
||||
if (!ofw_bus_is_compatible(dev, "ibm,ppc-xics") &&
|
||||
!ofw_bus_is_compatible(dev, "IBM,opal-xics"))
|
||||
return (ENXIO);
|
||||
|
||||
device_set_desc(dev, "External Interrupt Source Controller");
|
||||
@ -205,6 +217,15 @@ xicp_attach(device_t dev)
|
||||
sc->cpu_range[1] += sc->cpu_range[0];
|
||||
device_printf(dev, "Handling CPUs %d-%d\n", sc->cpu_range[0],
|
||||
sc->cpu_range[1]-1);
|
||||
#ifdef POWERNV
|
||||
} else if (ofw_bus_is_compatible(dev, "ibm,opal-intc")) {
|
||||
/*
|
||||
* For now run POWER9 XIVE interrupt controller in XICS
|
||||
* compatibility mode.
|
||||
*/
|
||||
sc->xics_emu = true;
|
||||
opal_call(OPAL_XIVE_RESET, XIVE_XICS_MODE_EMU);
|
||||
#endif
|
||||
} else {
|
||||
sc->cpu_range[0] = 0;
|
||||
sc->cpu_range[1] = mp_ncpus;
|
||||
@ -214,18 +235,26 @@ xicp_attach(device_t dev)
|
||||
if (mfmsr() & PSL_HV) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sc->cpu_range[1] - sc->cpu_range[0]; i++) {
|
||||
sc->mem[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
&i, RF_ACTIVE);
|
||||
if (sc->mem[i] == NULL) {
|
||||
device_printf(dev, "Could not alloc mem "
|
||||
"resource %d\n", i);
|
||||
return (ENXIO);
|
||||
if (sc->xics_emu) {
|
||||
opal_call(OPAL_INT_SET_CPPR, 0xff);
|
||||
for (i = 0; i < mp_ncpus; i++) {
|
||||
opal_call(OPAL_INT_SET_MFRR,
|
||||
pcpu_find(i)->pc_hwref, 0xff);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < sc->cpu_range[1] - sc->cpu_range[0]; i++) {
|
||||
sc->mem[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
&i, RF_ACTIVE);
|
||||
if (sc->mem[i] == NULL) {
|
||||
device_printf(dev, "Could not alloc mem "
|
||||
"resource %d\n", i);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Unmask interrupts on all cores */
|
||||
bus_write_1(sc->mem[i], 4, 0xff);
|
||||
bus_write_1(sc->mem[i], 12, 0xff);
|
||||
/* Unmask interrupts on all cores */
|
||||
bus_write_1(sc->mem[i], 4, 0xff);
|
||||
bus_write_1(sc->mem[i], 12, 0xff);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -316,19 +345,25 @@ xicp_dispatch(device_t dev, struct trapframe *tf)
|
||||
uint64_t xirr, junk;
|
||||
int i;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
#ifdef POWERNV
|
||||
if (mfmsr() & PSL_HV) {
|
||||
if ((mfmsr() & PSL_HV) && !sc->xics_emu) {
|
||||
regs = xicp_mem_for_cpu(PCPU_GET(hwref));
|
||||
KASSERT(regs != NULL,
|
||||
("Can't find regs for CPU %ld", (uintptr_t)PCPU_GET(hwref)));
|
||||
}
|
||||
#endif
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
for (;;) {
|
||||
/* Return value in R4, use the PFT call */
|
||||
if (regs) {
|
||||
xirr = bus_read_4(regs, 4);
|
||||
#ifdef POWERNV
|
||||
} else if (sc->xics_emu) {
|
||||
opal_call(OPAL_INT_GET_XIRR, &cpu_xirr[PCPU_GET(cpuid)],
|
||||
false);
|
||||
xirr = cpu_xirr[PCPU_GET(cpuid)];
|
||||
#endif
|
||||
} else {
|
||||
/* Return value in R4, use the PFT call */
|
||||
phyp_pft_hcall(H_XIRR, 0, 0, 0, 0, &xirr, &junk, &junk);
|
||||
@ -338,6 +373,10 @@ xicp_dispatch(device_t dev, struct trapframe *tf)
|
||||
if (xirr == 0) { /* No more pending interrupts? */
|
||||
if (regs)
|
||||
bus_write_1(regs, 4, 0xff);
|
||||
#ifdef POWERNV
|
||||
else if (sc->xics_emu)
|
||||
opal_call(OPAL_INT_SET_CPPR, 0xff);
|
||||
#endif
|
||||
else
|
||||
phyp_hcall(H_CPPR, (uint64_t)0xff);
|
||||
break;
|
||||
@ -348,6 +387,11 @@ xicp_dispatch(device_t dev, struct trapframe *tf)
|
||||
/* Clear IPI */
|
||||
if (regs)
|
||||
bus_write_1(regs, 12, 0xff);
|
||||
#ifdef POWERNV
|
||||
else if (sc->xics_emu)
|
||||
opal_call(OPAL_INT_SET_MFRR,
|
||||
PCPU_GET(hwref), 0xff);
|
||||
#endif
|
||||
else
|
||||
phyp_hcall(H_IPI, (uint64_t)(PCPU_GET(hwref)),
|
||||
0xff);
|
||||
@ -409,6 +453,9 @@ xicp_enable(device_t dev, u_int irq, u_int vector)
|
||||
static void
|
||||
xicp_eoi(device_t dev, u_int irq)
|
||||
{
|
||||
#ifdef POWERNV
|
||||
struct xicp_softc *sc;
|
||||
#endif
|
||||
uint64_t xirr;
|
||||
|
||||
if (irq == MAX_XICP_IRQS) /* Remap IPI interrupt to internal value */
|
||||
@ -416,9 +463,13 @@ xicp_eoi(device_t dev, u_int irq)
|
||||
xirr = irq | (XICP_PRIORITY << 24);
|
||||
|
||||
#ifdef POWERNV
|
||||
if (mfmsr() & PSL_HV)
|
||||
bus_write_4(xicp_mem_for_cpu(PCPU_GET(hwref)), 4, xirr);
|
||||
else
|
||||
if (mfmsr() & PSL_HV) {
|
||||
sc = device_get_softc(dev);
|
||||
if (sc->xics_emu)
|
||||
opal_call(OPAL_INT_EOI, xirr);
|
||||
else
|
||||
bus_write_4(xicp_mem_for_cpu(PCPU_GET(hwref)), 4, xirr);
|
||||
} else
|
||||
#endif
|
||||
phyp_hcall(H_EOI, xirr);
|
||||
}
|
||||
@ -428,11 +479,19 @@ xicp_ipi(device_t dev, u_int cpu)
|
||||
{
|
||||
|
||||
#ifdef POWERNV
|
||||
struct xicp_softc *sc;
|
||||
cpu = pcpu_find(cpu)->pc_hwref;
|
||||
|
||||
if (mfmsr() & PSL_HV)
|
||||
bus_write_1(xicp_mem_for_cpu(cpu), 12, XICP_PRIORITY);
|
||||
else
|
||||
if (mfmsr() & PSL_HV) {
|
||||
sc = device_get_softc(dev);
|
||||
if (sc->xics_emu) {
|
||||
int64_t rv;
|
||||
rv = opal_call(OPAL_INT_SET_MFRR, cpu, XICP_PRIORITY);
|
||||
if (rv != 0)
|
||||
device_printf(dev, "IPI SET_MFRR result: %ld\n", rv);
|
||||
} else
|
||||
bus_write_1(xicp_mem_for_cpu(cpu), 12, XICP_PRIORITY);
|
||||
} else
|
||||
#endif
|
||||
phyp_hcall(H_IPI, (uint64_t)cpu, XICP_PRIORITY);
|
||||
}
|
||||
@ -490,3 +549,18 @@ xicp_unmask(device_t dev, u_int irq)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef POWERNV
|
||||
/* This is only used on POWER9 systems with the XIVE's XICS emulation. */
|
||||
void
|
||||
xicp_smp_cpu_startup(void)
|
||||
{
|
||||
struct xicp_softc *sc;
|
||||
|
||||
if (mfmsr() & PSL_HV) {
|
||||
sc = device_get_softc(root_pic);
|
||||
|
||||
if (sc->xics_emu)
|
||||
opal_call(OPAL_INT_SET_CPPR, 0xff);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user