Index: head/sys/powerpc/aim/mp_cpudep.c =================================================================== --- head/sys/powerpc/aim/mp_cpudep.c +++ head/sys/powerpc/aim/mp_cpudep.c @@ -96,7 +96,7 @@ mtspr(SPR_LPID, 0); isync(); - mtspr(SPR_LPCR, LPCR_LPES); + mtspr(SPR_LPCR, lpcr); isync(); } #endif @@ -401,7 +401,7 @@ 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(); } Index: head/sys/powerpc/include/cpu.h =================================================================== --- head/sys/powerpc/include/cpu.h +++ head/sys/powerpc/include/cpu.h @@ -135,6 +135,7 @@ #ifdef __powerpc64__ extern void enter_idle_powerx(void); extern uint64_t can_wakeup; +extern register_t lpcr; #endif void cpu_halt(void); Index: head/sys/powerpc/include/spr.h =================================================================== --- head/sys/powerpc/include/spr.h +++ head/sys/powerpc/include/spr.h @@ -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 */ Index: head/sys/powerpc/powernv/opal.h =================================================================== --- head/sys/powerpc/powernv/opal.h +++ head/sys/powerpc/powernv/opal.h @@ -73,7 +73,12 @@ #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 Index: head/sys/powerpc/powernv/platform_powernv.c =================================================================== --- head/sys/powerpc/powernv/platform_powernv.c +++ head/sys/powerpc/powernv/platform_powernv.c @@ -59,6 +59,7 @@ 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 @@ 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 @@ static void powernv_smp_ap_init(platform_t platform) { + + xicp_smp_cpu_startup(); } static void Index: head/sys/powerpc/powerpc/cpu.c =================================================================== --- head/sys/powerpc/powerpc/cpu.c +++ head/sys/powerpc/powerpc/cpu.c @@ -240,6 +240,10 @@ 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", Index: head/sys/powerpc/pseries/xics.c =================================================================== --- head/sys/powerpc/pseries/xics.c +++ head/sys/powerpc/pseries/xics.c @@ -61,6 +61,9 @@ #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_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 @@ int cpu; } intvecs[256]; int nintvecs; + bool xics_emu; }; static driver_t xicp_driver = { @@ -131,6 +139,8 @@ 0 }; +static uint32_t cpu_xirr[MAXCPU]; + static devclass_t xicp_devclass; static devclass_t xics_devclass; @@ -161,7 +171,8 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ { #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 @@ } } +#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