svn commit: r277635 - in projects/powernv/powerpc: powernv pseries
Nathan Whitehorn
nwhitehorn at FreeBSD.org
Sat Jan 24 02:16:54 UTC 2015
Author: nwhitehorn
Date: Sat Jan 24 02:16:53 2015
New Revision: 277635
URL: https://svnweb.freebsd.org/changeset/base/277635
Log:
Add a first-draft PIC driver. This does not yet have actual SMP support on
OPAL since we have to deal with the fact that these machines do not have
a global root PIC: instead of an interrupt tree, they have an interrupt web
with per-CPU controllers. This is a complication to deal with later.
With one CPU, however, this is enough to boot multiuser in the simulator.
Sponsored by: FreeBSD Foundation
Modified:
projects/powernv/powerpc/powernv/opal.h
projects/powernv/powerpc/pseries/xics.c
Modified: projects/powernv/powerpc/powernv/opal.h
==============================================================================
--- projects/powernv/powerpc/powernv/opal.h Sat Jan 24 02:12:00 2015 (r277634)
+++ projects/powernv/powerpc/powernv/opal.h Sat Jan 24 02:16:53 2015 (r277635)
@@ -40,6 +40,8 @@ int opal_call(uint64_t token, ...);
#define OPAL_CONSOLE_WRITE 1
#define OPAL_CONSOLE_READ 2
+#define OPAL_SET_XIVE 19
+#define OPAL_GET_XIVE 20
#define OPAL_START_CPU 41
#define OPAL_SUCCESS 0
Modified: projects/powernv/powerpc/pseries/xics.c
==============================================================================
--- projects/powernv/powerpc/pseries/xics.c Sat Jan 24 02:12:00 2015 (r277634)
+++ projects/powernv/powerpc/pseries/xics.c Sat Jan 24 02:16:53 2015 (r277635)
@@ -46,6 +46,8 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <powerpc/powernv/opal.h>
+
#include "phyp-hvcall.h"
#include "pic_if.h"
@@ -93,6 +95,8 @@ static device_method_t xics_methods[] =
struct xicp_softc {
struct mtx sc_mtx;
+ struct resource *mem;
+ int memrid;
int ibm_int_on;
int ibm_int_off;
@@ -103,6 +107,7 @@ struct xicp_softc {
struct {
int irq;
int vector;
+ int cpu;
} intvecs[256];
int nintvecs;
};
@@ -137,7 +142,7 @@ xicp_probe(device_t dev)
if (!ofw_bus_is_compatible(dev, "ibm,ppc-xicp"))
return (ENXIO);
- device_set_desc(dev, "PAPR virtual interrupt controller");
+ device_set_desc(dev, "External Interrupt Presentation Controller");
return (BUS_PROBE_GENERIC);
}
@@ -151,7 +156,7 @@ xics_probe(device_t dev)
if (!ofw_bus_is_compatible(dev, "ibm,ppc-xics"))
return (ENXIO);
- device_set_desc(dev, "PAPR virtual interrupt source");
+ device_set_desc(dev, "External Interrupt Source Controller");
return (BUS_PROBE_GENERIC);
}
@@ -161,14 +166,31 @@ xicp_attach(device_t dev)
struct xicp_softc *sc = device_get_softc(dev);
phandle_t phandle = ofw_bus_get_node(dev);
+ if (rtas_exists()) {
+ sc->ibm_int_on = rtas_token_lookup("ibm,int-on");
+ sc->ibm_int_off = rtas_token_lookup("ibm,int-off");
+ sc->ibm_set_xive = rtas_token_lookup("ibm,set-xive");
+ sc->ibm_get_xive = rtas_token_lookup("ibm,get-xive");
+ } else if (opal_check() == 0) {
+ /* No init needed */
+ } else {
+ device_printf(dev, "Cannot attach without RTAS or OPAL\n");
+ return (ENXIO);
+ }
+
+ if (mfmsr() & PSL_HV) {
+ sc->memrid = 0;
+ sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->memrid, RF_ACTIVE);
+ if (sc->mem == NULL) {
+ device_printf(dev, "Could not alloc mem resource\n");
+ return (ENXIO);
+ }
+ }
+
mtx_init(&sc->sc_mtx, "XICP", NULL, MTX_DEF);
sc->nintvecs = 0;
- sc->ibm_int_on = rtas_token_lookup("ibm,int-on");
- sc->ibm_int_off = rtas_token_lookup("ibm,int-off");
- sc->ibm_set_xive = rtas_token_lookup("ibm,set-xive");
- sc->ibm_get_xive = rtas_token_lookup("ibm,get-xive");
-
powerpc_register_pic(dev, OF_xref_from_node(phandle), MAX_XICP_IRQS,
1 /* Number of IPIs */, FALSE);
root_pic = dev;
@@ -197,6 +219,7 @@ xicp_bind(device_t dev, u_int irq, cpuse
{
struct xicp_softc *sc = device_get_softc(dev);
cell_t status, cpu;
+ int i;
/*
* This doesn't appear to actually support affinity groups, so just
@@ -205,8 +228,20 @@ xicp_bind(device_t dev, u_int irq, cpuse
CPU_FOREACH(cpu)
if (CPU_ISSET(cpu, &cpumask)) break;
- rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY,
- &status);
+ /* XXX: super inefficient */
+ for (i = 0; i < sc->nintvecs; i++) {
+ if (sc->intvecs[i].irq == irq) {
+ sc->intvecs[i].cpu = cpu;
+ break;
+ }
+ }
+ KASSERT(i < sc->nintvecs, ("Binding non-configured interrupt"));
+
+ if (rtas_exists())
+ rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu,
+ XICP_PRIORITY, &status);
+ else
+ opal_call(OPAL_SET_XIVE, irq, cpu, XICP_PRIORITY);
}
static void
@@ -218,18 +253,30 @@ xicp_dispatch(device_t dev, struct trapf
sc = device_get_softc(dev);
for (;;) {
- /* Return value in R4, use the PFT call */
- phyp_pft_hcall(H_XIRR, 0, 0, 0, 0, &xirr, &junk, &junk);
+ if (sc->mem) {
+ xirr = bus_read_4(sc->mem, 4);
+ } else {
+ /* Return value in R4, use the PFT call */
+ phyp_pft_hcall(H_XIRR, 0, 0, 0, 0, &xirr, &junk, &junk);
+ }
xirr &= 0x00ffffff;
if (xirr == 0) { /* No more pending interrupts? */
- phyp_hcall(H_CPPR, (uint64_t)0xff);
+ if (sc->mem)
+ bus_write_1(sc->mem, 4, 0xff);
+ else
+ phyp_hcall(H_CPPR, (uint64_t)0xff);
break;
}
if (xirr == XICP_IPI) { /* Magic number for IPIs */
xirr = MAX_XICP_IRQS; /* Map to FreeBSD magic */
- phyp_hcall(H_IPI, (uint64_t)(PCPU_GET(cpuid)),
- 0xff); /* Clear IPI */
+
+ /* Clear IPI */
+ if (sc->mem)
+ bus_write_1(sc->mem, 12, 0xff);
+ else
+ phyp_hcall(H_IPI, (uint64_t)(PCPU_GET(cpuid)),
+ 0xff);
}
/* XXX: super inefficient */
@@ -254,9 +301,13 @@ xicp_enable(device_t dev, u_int irq, u_i
KASSERT(sc->nintvecs + 1 < sizeof(sc->intvecs)/sizeof(sc->intvecs[0]),
("Too many XICP interrupts"));
+ /* Bind to this CPU to start: distrib. ID is last entry in gserver# */
+ cpu = PCPU_GET(cpuid);
+
mtx_lock(&sc->sc_mtx);
sc->intvecs[sc->nintvecs].irq = irq;
sc->intvecs[sc->nintvecs].vector = vector;
+ sc->intvecs[sc->nintvecs].cpu = cpu;
mb();
sc->nintvecs++;
mtx_unlock(&sc->sc_mtx);
@@ -265,30 +316,41 @@ xicp_enable(device_t dev, u_int irq, u_i
if (irq == MAX_XICP_IRQS)
return;
- /* Bind to this CPU to start: distrib. ID is last entry in gserver# */
- cpu = PCPU_GET(cpuid);
- rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu, XICP_PRIORITY,
- &status);
- xicp_unmask(dev, irq);
+ if (rtas_exists()) {
+ rtas_call_method(sc->ibm_set_xive, 3, 1, irq, cpu,
+ XICP_PRIORITY, &status);
+ xicp_unmask(dev, irq);
+ } else {
+ opal_call(OPAL_SET_XIVE, irq, cpu, XICP_PRIORITY);
+ /* Unmask implicit for OPAL */
+ }
}
static void
xicp_eoi(device_t dev, u_int irq)
{
uint64_t xirr;
+ struct xicp_softc *sc = device_get_softc(dev);
if (irq == MAX_XICP_IRQS) /* Remap IPI interrupt to internal value */
irq = XICP_IPI;
xirr = irq | (XICP_PRIORITY << 24);
- phyp_hcall(H_EOI, xirr);
+ if (sc->mem)
+ bus_write_4(sc->mem, 4, xirr);
+ else
+ phyp_hcall(H_EOI, xirr);
}
static void
xicp_ipi(device_t dev, u_int cpu)
{
+ struct xicp_softc *sc = device_get_softc(dev);
- phyp_hcall(H_IPI, (uint64_t)cpu, XICP_PRIORITY);
+ if (sc->mem)
+ bus_write_1(sc->mem, 12, XICP_PRIORITY); /* Pick node! */
+ else
+ phyp_hcall(H_IPI, (uint64_t)cpu, XICP_PRIORITY);
}
static void
@@ -296,11 +358,22 @@ xicp_mask(device_t dev, u_int irq)
{
struct xicp_softc *sc = device_get_softc(dev);
cell_t status;
+ int i;
if (irq == MAX_XICP_IRQS)
return;
- rtas_call_method(sc->ibm_int_off, 1, 1, irq, &status);
+ if (rtas_exists()) {
+ rtas_call_method(sc->ibm_int_off, 1, 1, irq, &status);
+ } else {
+ for (i = 0; i < sc->nintvecs; i++) {
+ if (sc->intvecs[i].irq == irq) {
+ break;
+ }
+ }
+ KASSERT(i < sc->nintvecs, ("Masking unconfigured interrupt"));
+ opal_call(OPAL_SET_XIVE, irq, sc->intvecs[i].cpu, 0xff);
+ }
}
static void
@@ -308,10 +381,22 @@ xicp_unmask(device_t dev, u_int irq)
{
struct xicp_softc *sc = device_get_softc(dev);
cell_t status;
+ int i;
if (irq == MAX_XICP_IRQS)
return;
- rtas_call_method(sc->ibm_int_on, 1, 1, irq, &status);
+ if (rtas_exists()) {
+ rtas_call_method(sc->ibm_int_on, 1, 1, irq, &status);
+ } else {
+ for (i = 0; i < sc->nintvecs; i++) {
+ if (sc->intvecs[i].irq == irq) {
+ break;
+ }
+ }
+ KASSERT(i < sc->nintvecs, ("Unmasking unconfigured interrupt"));
+ opal_call(OPAL_SET_XIVE, irq, sc->intvecs[i].cpu,
+ XICP_PRIORITY);
+ }
}
More information about the svn-src-projects
mailing list