Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 5 Nov 2011 16:04:57 +0000 (UTC)
From:      Nathan Whitehorn <nwhitehorn@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r227109 - in projects/pseries: conf powerpc/pseries
Message-ID:  <201111051604.pA5G4v9a074651@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: nwhitehorn
Date: Sat Nov  5 16:04:57 2011
New Revision: 227109
URL: http://svn.freebsd.org/changeset/base/227109

Log:
  Add the beginnings of the pSeries PIC driver. IPIs work, at least, which
  is all I could test in QEMU. A few other changes (to RTAS and the platform
  infrastructure) will be required to make non-IPIs work.

Added:
  projects/pseries/powerpc/pseries/xics.c   (contents, props changed)
Modified:
  projects/pseries/conf/files.powerpc

Modified: projects/pseries/conf/files.powerpc
==============================================================================
--- projects/pseries/conf/files.powerpc	Sat Nov  5 12:01:51 2011	(r227108)
+++ projects/pseries/conf/files.powerpc	Sat Nov  5 16:04:57 2011	(r227109)
@@ -219,6 +219,7 @@ powerpc/pseries/phyp_console.c	optional	
 powerpc/pseries/platform_chrp.c	optional	pseries
 powerpc/pseries/rtas_dev.c	optional	pseries
 powerpc/pseries/rtas_pci.c	optional	pseries pci
+powerpc/pseries/xics.c		optional	pseries powerpc64
 powerpc/psim/iobus.c 		optional	psim
 powerpc/psim/ata_iobus.c	optional	ata psim
 powerpc/psim/openpic_iobus.c	optional	psim

Added: projects/pseries/powerpc/pseries/xics.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/pseries/powerpc/pseries/xics.c	Sat Nov  5 16:04:57 2011	(r227109)
@@ -0,0 +1,264 @@
+/*-
+ * Copyright 2011 Nathan Whitehorn
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/smp.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
+#include <machine/rtas.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "phyp-hvcall.h"
+#include "pic_if.h"
+
+#define XICS_PRIORITY	5	/* Random non-zero number */
+#define XICS_IPI	2
+#define MAX_XICS_IRQS	255	/* XXX: Should be 2^24, but causes problem */
+
+static int	xics_probe(device_t);
+static int	xics_attach(device_t);
+
+static void	xics_bind(device_t dev, u_int irq, cpuset_t cpumask);
+static void	xics_dispatch(device_t, struct trapframe *);
+static void	xics_enable(device_t, u_int, u_int);
+static void	xics_eoi(device_t, u_int);
+static void	xics_ipi(device_t, u_int);
+static void	xics_mask(device_t, u_int);
+static void	xics_unmask(device_t, u_int);
+
+static device_method_t  xics_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe,		xics_probe),
+	DEVMETHOD(device_attach,	xics_attach),
+
+	/* PIC interface */
+	DEVMETHOD(pic_bind,		xics_bind),
+	DEVMETHOD(pic_dispatch,		xics_dispatch),
+	DEVMETHOD(pic_enable,		xics_enable),
+	DEVMETHOD(pic_eoi,		xics_eoi),
+	DEVMETHOD(pic_ipi,		xics_ipi),
+	DEVMETHOD(pic_mask,		xics_mask),
+	DEVMETHOD(pic_unmask,		xics_unmask),
+
+	{ 0, 0 },
+};
+
+struct xics_softc {
+	int ibm_int_on;
+	int ibm_int_off;
+	int ibm_get_xive;
+	int ibm_set_xive;
+
+	/* XXX: inefficient -- hash table? tree? */
+	struct {
+		int irq;
+		int vector;
+	} intvecs[256];
+	int nintvecs;
+};
+
+static driver_t xics_driver = {
+	"xics",
+	xics_methods,
+	sizeof(struct xics_softc)
+};
+
+static devclass_t xics_devclass;
+
+DRIVER_MODULE(xics, nexus, xics_driver, xics_devclass, 0, 0);
+
+static int
+xics_probe(device_t dev)
+{
+	if (ofw_bus_get_name(dev) == NULL || strcmp(ofw_bus_get_name(dev),
+	    "interrupt-controller") != 0)
+		return (ENXIO);
+
+	if (!ofw_bus_is_compatible(dev, "ibm,ppc-xicp"))
+		return (ENXIO);
+
+	device_set_desc(dev, "PAPR virtual interrupt controller");
+	return (BUS_PROBE_GENERIC);
+}
+
+static int
+xics_attach(device_t dev)
+{
+	struct xics_softc *sc;
+
+	sc = device_get_softc(dev);
+	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, ofw_bus_get_node(dev), MAX_XICS_IRQS,
+	    1 /* Number of IPIs */, FALSE);
+	return (0);
+}
+
+/*
+ * PIC I/F methods.
+ */
+
+static void
+xics_bind(device_t dev, u_int irq, cpuset_t cpumask)
+{
+	struct xics_softc *sc = device_get_softc(dev);
+	uint64_t status;
+
+	/*
+	 * XXX: This is very special and just needs a mask.
+	 * For the moment, just play dirty and get the first word.
+	 */
+	rtas_call_method(sc->ibm_set_xive, 3, 1, (uint64_t)irq,
+	    cpumask.__bits[0], XICS_PRIORITY, &status);
+}
+
+static void
+xics_dispatch(device_t dev, struct trapframe *tf)
+{
+	struct xics_softc *sc;
+	uint64_t xirr, junk;
+	int i;
+
+	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);
+		xirr &= 0x00ffffff;
+
+		if (xirr == 0) { /* No more pending interrupts? */
+			phyp_hcall(H_CPPR, (uint64_t)0xff);
+			break;
+		}
+		if (xirr == XICS_IPI) {		/* Magic number for IPIs */
+			xirr = MAX_XICS_IRQS;	/* Map to FreeBSD magic */
+			phyp_hcall(H_IPI, (uint64_t)(PCPU_GET(cpuid)),
+			    0xff); /* Clear IPI */
+		}
+
+		/* XXX: super inefficient */
+		for (i = 0; i < sc->nintvecs; i++) {
+			if (sc->intvecs[i].irq == xirr)
+				break;
+		}
+
+		KASSERT(i < sc->nintvecs, ("Unmapped XIRR"));
+		powerpc_dispatch_intr(sc->intvecs[i].vector, tf);
+	}
+}
+
+static void
+xics_enable(device_t dev, u_int irq, u_int vector)
+{
+	struct xics_softc *sc;
+	uint64_t status, cpumask;
+	int i;
+
+	sc = device_get_softc(dev);
+
+	KASSERT(sc->nintvecs + 1 < sizeof(sc->intvecs)/sizeof(sc->intvecs[0]),
+	    ("Too many XICS interrupts"));
+
+	/* XXX: not thread safe */
+	sc->intvecs[sc->nintvecs].irq = irq;
+	sc->intvecs[sc->nintvecs].vector = vector;
+	sc->nintvecs++;
+
+	/* IPIs are also enabled */
+	if (irq == MAX_XICS_IRQS)
+		return;
+
+	/* Bind to all CPUs to start */
+	cpumask = 0;
+	CPU_FOREACH(i)
+		cpumask |= (1ULL << i);
+
+	rtas_call_method(sc->ibm_set_xive, 3, 1, (uint64_t)irq, cpumask,
+	    XICS_PRIORITY, &status);
+	xics_unmask(dev, irq);
+}
+
+static void
+xics_eoi(device_t dev, u_int irq)
+{
+	uint64_t xirr;
+
+	if (irq == MAX_XICS_IRQS) /* Remap IPI interrupt to internal value */
+		irq = XICS_IPI;
+	xirr = irq | (XICS_PRIORITY << 24);
+
+	phyp_hcall(H_EOI, xirr);
+}
+
+static void
+xics_ipi(device_t dev, u_int cpu)
+{
+
+	phyp_hcall(H_IPI, (uint64_t)cpu, XICS_PRIORITY);
+}
+
+static void
+xics_mask(device_t dev, u_int irq)
+{
+	struct xics_softc *sc = device_get_softc(dev);
+	uint64_t status;
+
+	if (irq == MAX_XICS_IRQS)
+		return;
+
+	/* XXX: These RTAS calls are problematic, since RTAS needs locks */
+	rtas_call_method(sc->ibm_int_off, 1, 1, (uint64_t)irq, &status);
+}
+
+static void
+xics_unmask(device_t dev, u_int irq)
+{
+	struct xics_softc *sc = device_get_softc(dev);
+	uint64_t status;
+
+	if (irq == MAX_XICS_IRQS)
+		return;
+
+	/* XXX: These RTAS calls are problematic, since RTAS needs locks */
+	rtas_call_method(sc->ibm_int_on, 1, 1, (uint64_t)irq, &status);
+}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201111051604.pA5G4v9a074651>