Author: wma
Date: Thu Jan 11 07:40:06 2018
New Revision: 327810
URL: https://svnweb.freebsd.org/changeset/base/327810

Log:
  PowerNV: initial support for OPAL
  
  OPAL is a dedicated firmware acting as a hypervisor.
  Add generic functions to provide all access.
  
  Created by:            Nathan Whitehorn <n...@freebsd.org>
  Submitted by:          Wojciech Macek <w...@freebsd.org>

Added:
  head/sys/powerpc/powernv/
  head/sys/powerpc/powernv/opal.c   (contents, props changed)
  head/sys/powerpc/powernv/opal.h   (contents, props changed)
  head/sys/powerpc/powernv/opal_console.c   (contents, props changed)
  head/sys/powerpc/powernv/opalcall.S   (contents, props changed)
  head/sys/powerpc/powernv/platform_powernv.c   (contents, props changed)
Modified:
  head/sys/conf/files.powerpc
  head/sys/conf/options.powerpc
  head/sys/powerpc/conf/GENERIC64

Modified: head/sys/conf/files.powerpc
==============================================================================
--- head/sys/conf/files.powerpc Thu Jan 11 07:35:14 2018        (r327809)
+++ head/sys/conf/files.powerpc Thu Jan 11 07:40:06 2018        (r327810)
@@ -183,6 +183,10 @@ powerpc/powermac/smusat.c  optional        powermac smu
 powerpc/powermac/uninorth.c    optional        powermac
 powerpc/powermac/uninorthpci.c optional        powermac pci
 powerpc/powermac/vcoregpio.c   optional        powermac 
+powerpc/powernv/opal.c         optional        powernv
+powerpc/powernv/opal_console.c optional        powernv
+powerpc/powernv/opalcall.S     optional        powernv
+powerpc/powernv/platform_powernv.c optional    powernv
 powerpc/powerpc/altivec.c      optional        powerpc | powerpc64
 powerpc/powerpc/autoconf.c     standard
 powerpc/powerpc/bcopy.c                standard

Modified: head/sys/conf/options.powerpc
==============================================================================
--- head/sys/conf/options.powerpc       Thu Jan 11 07:35:14 2018        
(r327809)
+++ head/sys/conf/options.powerpc       Thu Jan 11 07:40:06 2018        
(r327810)
@@ -23,6 +23,7 @@ MPC85XX                       opt_platform.h
 POWERMAC               opt_platform.h
 PS3                    opt_platform.h
 MAMBO
+POWERNV
 PSERIES
 PSIM
 

Modified: head/sys/powerpc/conf/GENERIC64
==============================================================================
--- head/sys/powerpc/conf/GENERIC64     Thu Jan 11 07:35:14 2018        
(r327809)
+++ head/sys/powerpc/conf/GENERIC64     Thu Jan 11 07:40:06 2018        
(r327810)
@@ -31,6 +31,7 @@ options       POWERMAC                #NewWorld Apple 
PowerMacs
 options        PS3                     #Sony Playstation 3
 options        MAMBO                   #IBM Mambo Full System Simulator
 options        PSERIES                 #PAPR-compliant systems (e.g. IBM p)
+options                POWERNV                 #Non-virtualized OpenPOWER 
systems
 
 options                FDT                     #Flattened Device Tree
 options        SCHED_ULE               #ULE scheduler

Added: head/sys/powerpc/powernv/opal.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/powerpc/powernv/opal.c     Thu Jan 11 07:40:06 2018        
(r327810)
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (C) 2015 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * 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 TOOLS GMBH 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 <dev/ofw/openfirm.h>
+
+#include "opal.h"
+
+extern uint64_t opal_entrypoint;
+extern uint64_t opal_data;
+extern uint64_t opal_msr;
+
+static int opal_initialized = 0;
+
+int
+opal_check(void)
+{
+       phandle_t opal;
+       cell_t val[2];
+
+       if (opal_initialized)
+               return (0);
+
+       opal = OF_finddevice("/ibm,opal");
+       if (opal == -1)
+               return (ENOENT);
+
+       if (!OF_hasprop(opal, "opal-base-address") ||
+           !OF_hasprop(opal, "opal-entry-address"))
+               return (ENOENT);
+       
+       OF_getencprop(opal, "opal-base-address", val, sizeof(val));
+       opal_data = ((uint64_t)val[0] << 32) | val[1];
+       OF_getencprop(opal, "opal-entry-address", val, sizeof(val));
+       opal_entrypoint = ((uint64_t)val[0] << 32) | val[1];
+
+       opal_msr = mfmsr() & ~(PSL_EE | PSL_IR | PSL_DR | PSL_SE);
+
+       opal_initialized = 1;
+
+       return (0);
+}
+

Added: head/sys/powerpc/powernv/opal.h
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/powerpc/powernv/opal.h     Thu Jan 11 07:40:06 2018        
(r327810)
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2015 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
+ */
+
+#ifndef _POWERNV_OPAL_H
+#define _POWERNV_OPAL_H
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/* Check if OPAL is correctly instantiated. Will try to instantiate it. */
+int opal_check(void);
+
+/* Call an OPAL method. Any pointers passed must be real-mode accessible! */
+int opal_call(uint64_t token, ...);
+
+#define OPAL_CONSOLE_WRITE     1
+#define OPAL_CONSOLE_READ      2
+#define OPAL_START_CPU         41
+
+#define OPAL_SUCCESS           0
+#define        OPAL_BUSY_EVENT         -12
+
+#endif

Added: head/sys/powerpc/powernv/opal_console.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/powerpc/powernv/opal_console.c     Thu Jan 11 07:40:06 2018        
(r327810)
@@ -0,0 +1,441 @@
+/*-
+ * Copyright (C) 2011,2015 by Nathan Whitehorn. All rights reserved.
+ *
+ * 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 TOOLS GMBH 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kdb.h>
+#include <sys/kernel.h>
+#include <sys/priv.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/types.h>
+#include <sys/conf.h>
+#include <sys/cons.h>
+#include <sys/tty.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+
+#include "opal.h"
+#include "uart_if.h"
+
+struct uart_opal_softc {
+       device_t dev;
+       phandle_t node;
+       int vtermid;
+
+       struct tty *tp;
+       struct resource *irqres;
+       int irqrid;
+       struct callout callout;
+       void *sc_icookie;
+       int polltime;
+
+       struct mtx sc_mtx;
+       int protocol;
+
+       char opal_inbuf[16];
+       uint64_t inbuflen;
+       uint8_t outseqno;
+};
+
+static struct uart_opal_softc  *console_sc = NULL;
+#if defined(KDB)
+static int                     alt_break_state;
+#endif
+
+enum {
+       OPAL_RAW, OPAL_HVSI
+};
+
+#define VS_DATA_PACKET_HEADER          0xff
+#define VS_CONTROL_PACKET_HEADER       0xfe
+#define  VSV_SET_MODEM_CTL             0x01
+#define  VSV_MODEM_CTL_UPDATE          0x02
+#define  VSV_RENEGOTIATE_CONNECTION    0x03
+#define VS_QUERY_PACKET_HEADER         0xfd
+#define  VSV_SEND_VERSION_NUMBER       0x01
+#define  VSV_SEND_MODEM_CTL_STATUS     0x02
+#define VS_QUERY_RESPONSE_PACKET_HEADER        0xfc
+
+static int uart_opal_probe(device_t dev);
+static int uart_opal_attach(device_t dev);
+static void uart_opal_intr(void *v);
+
+static device_method_t uart_opal_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         uart_opal_probe),
+       DEVMETHOD(device_attach,        uart_opal_attach),
+
+       DEVMETHOD_END
+};
+
+static driver_t uart_opal_driver = {
+       "uart",
+       uart_opal_methods,
+       sizeof(struct uart_opal_softc),
+};
+ 
+DRIVER_MODULE(uart_opal, opalcons, uart_opal_driver, uart_devclass, 0, 0);
+
+static cn_probe_t uart_opal_cnprobe;
+static cn_init_t uart_opal_cninit;
+static cn_term_t uart_opal_cnterm;
+static cn_getc_t uart_opal_cngetc;
+static cn_putc_t uart_opal_cnputc;
+static cn_grab_t uart_opal_cngrab;
+static cn_ungrab_t uart_opal_cnungrab;
+
+CONSOLE_DRIVER(uart_opal);
+
+static void uart_opal_ttyoutwakeup(struct tty *tp);
+
+static struct ttydevsw uart_opal_tty_class = {
+       .tsw_flags      = TF_INITLOCK|TF_CALLOUT,
+       .tsw_outwakeup  = uart_opal_ttyoutwakeup,
+};
+
+static int
+uart_opal_probe_node(struct uart_opal_softc *sc)
+{
+       phandle_t node = sc->node;
+       uint32_t reg;
+       char buf[64];
+
+       sc->inbuflen = 0;
+       sc->outseqno = 0;
+
+       if (OF_getprop(node, "device_type", buf, sizeof(buf)) <= 0)
+               return (ENXIO);
+       if (strcmp(buf, "serial") != 0)
+               return (ENXIO);
+
+       reg = -1;
+       OF_getprop(node, "reg", &reg, sizeof(reg));
+       if (reg == -1)
+               return (ENXIO);
+       sc->vtermid = reg;
+       sc->node = node;
+
+       if (OF_getprop(node, "compatible", buf, sizeof(buf)) <= 0)
+               return (ENXIO);
+       if (strcmp(buf, "ibm,opal-console-raw") == 0) {
+               sc->protocol = OPAL_RAW;
+               return (0);
+       } else if (strcmp(buf, "ibm,opal-console-hvsi") == 0) {
+               sc->protocol = OPAL_HVSI;
+               return (0);
+       }
+
+       return (ENXIO);
+}
+
+static int
+uart_opal_probe(device_t dev)
+{
+       struct uart_opal_softc sc;
+       int err;
+
+       sc.node = ofw_bus_get_node(dev);
+       err = uart_opal_probe_node(&sc);
+       if (err != 0)
+               return (err);
+
+       device_set_desc(dev, "OPAL Serial Port");
+
+       return (err);
+}
+
+static void
+uart_opal_cnprobe(struct consdev *cp)
+{
+       char buf[64];
+       phandle_t input, chosen;
+       static struct uart_opal_softc sc;
+
+       if (opal_check() != 0)
+               goto fail;
+
+       if ((chosen = OF_finddevice("/chosen")) == -1)
+               goto fail;
+
+       /* Check if OF has an active stdin/stdout */
+       if (OF_getprop(chosen, "linux,stdout-path", buf, sizeof(buf)) <= 0)
+               goto fail;
+       
+       input = OF_finddevice(buf);
+       if (input == -1)
+               goto fail;
+
+       sc.node = input;
+       if (uart_opal_probe_node(&sc) != 0)
+               goto fail;
+       mtx_init(&sc.sc_mtx, "uart_opal", NULL, MTX_SPIN | MTX_QUIET |
+           MTX_NOWITNESS);
+
+       cp->cn_pri = CN_NORMAL;
+       console_sc = &sc;
+       return;
+       
+fail:
+       cp->cn_pri = CN_DEAD;
+       return;
+}
+
+static int
+uart_opal_attach(device_t dev)
+{
+       struct uart_opal_softc *sc;
+       int unit;
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+       sc->node = ofw_bus_get_node(dev);
+       uart_opal_probe_node(sc);
+
+       unit = device_get_unit(dev);
+       sc->tp = tty_alloc(&uart_opal_tty_class, sc);
+       mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL,
+           MTX_SPIN | MTX_QUIET | MTX_NOWITNESS);
+
+       if (console_sc != NULL && console_sc->vtermid == sc->vtermid) {
+               sc->outseqno = console_sc->outseqno;
+               console_sc = sc;
+               sprintf(uart_opal_consdev.cn_name, "ttyu%r", unit);
+               tty_init_console(sc->tp, 0);
+       }
+
+       sc->irqrid = 0;
+       sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqrid,
+           RF_ACTIVE | RF_SHAREABLE);
+       if (sc->irqres != NULL) {
+               bus_setup_intr(dev, sc->irqres, INTR_TYPE_TTY | INTR_MPSAFE,
+                   NULL, uart_opal_intr, sc, &sc->sc_icookie);
+       } else {
+               callout_init(&sc->callout, CALLOUT_MPSAFE);
+               sc->polltime = hz / 20;
+               if (sc->polltime < 1)
+                       sc->polltime = 1;
+               callout_reset(&sc->callout, sc->polltime, uart_opal_intr, sc);
+       }
+
+       tty_makedev(sc->tp, NULL, "u%r", unit);
+
+       return (0);
+}
+
+static void
+uart_opal_cninit(struct consdev *cp)
+{
+
+       strcpy(cp->cn_name, "opalcons");
+}
+
+static void
+uart_opal_cnterm(struct consdev *cp)
+{
+}
+
+static int
+uart_opal_get(struct uart_opal_softc *sc, void *buffer, size_t bufsize)
+{
+       int err;
+       int hdr = 0;
+
+       if (sc->protocol == OPAL_RAW) {
+               uint64_t len = bufsize;
+               uint64_t olen = (uint64_t)&len;
+               uint64_t obuf = (uint64_t)buffer;
+
+               if (pmap_bootstrapped) {
+                       olen = vtophys(&len);
+                       obuf = vtophys(buffer);
+               }
+
+               err = opal_call(OPAL_CONSOLE_READ, sc->vtermid, olen, obuf);
+               if (err != OPAL_SUCCESS)
+                       return (-1);
+
+               bufsize = len;
+       } else {
+               uart_lock(&sc->sc_mtx);
+               if (sc->inbuflen == 0) {
+                       err = opal_call(OPAL_CONSOLE_READ, sc->vtermid,
+                           &sc->inbuflen, sc->opal_inbuf);
+                       if (err != OPAL_SUCCESS) {
+                               uart_unlock(&sc->sc_mtx);
+                               return (-1);
+                       }
+                       hdr = 1; 
+               }
+
+               if (sc->inbuflen == 0) {
+                       uart_unlock(&sc->sc_mtx);
+                       return (0);
+               }
+
+               if (bufsize > sc->inbuflen)
+                       bufsize = sc->inbuflen;
+
+               if (hdr == 1) {
+                       sc->inbuflen = sc->inbuflen - 4;
+                       /* The HVSI protocol has a 4 byte header, skip it */
+                       memmove(&sc->opal_inbuf[0], &sc->opal_inbuf[4],
+                           sc->inbuflen);
+               }
+
+               memcpy(buffer, sc->opal_inbuf, bufsize);
+               sc->inbuflen -= bufsize;
+               if (sc->inbuflen > 0)
+                       memmove(&sc->opal_inbuf[0], &sc->opal_inbuf[bufsize],
+                           sc->inbuflen);
+
+               uart_unlock(&sc->sc_mtx);
+       }
+
+       return (bufsize);
+}
+
+static int
+uart_opal_put(struct uart_opal_softc *sc, void *buffer, size_t bufsize)
+{
+       uint16_t seqno;
+       uint64_t len = bufsize;
+       char    cbuf[16];
+       int     err;
+       uint64_t olen = (uint64_t)&len;
+       uint64_t obuf = (uint64_t)cbuf;
+
+       if (pmap_bootstrapped)
+               olen = vtophys(&len);
+
+       if (sc->protocol == OPAL_RAW) {
+               if (pmap_bootstrapped)
+                       obuf = vtophys(buffer);
+               else
+                       obuf = (uint64_t)(buffer);
+
+               err = opal_call(OPAL_CONSOLE_WRITE, sc->vtermid, olen, obuf);
+       } else {
+               if (pmap_bootstrapped)
+                       obuf = vtophys(cbuf);
+               uart_lock(&sc->sc_mtx);
+               if (bufsize > 12)
+                       bufsize = 12;
+               seqno = sc->outseqno++;
+               cbuf[0] = VS_DATA_PACKET_HEADER;
+               cbuf[1] = 4 + bufsize; /* total length */
+               cbuf[2] = (seqno >> 8) & 0xff;
+               cbuf[3] = seqno & 0xff;
+               memcpy(&cbuf[4], buffer, bufsize);
+               len = 4 + bufsize;
+               err = opal_call(OPAL_CONSOLE_WRITE, sc->vtermid, olen, obuf);
+               uart_unlock(&sc->sc_mtx);
+
+               len -= 4;
+       }
+
+#if 0
+       if (err != OPAL_SUCCESS)
+               len = 0;
+#endif
+
+       return (len);
+}
+
+static int
+uart_opal_cngetc(struct consdev *cp)
+{
+       unsigned char c;
+       int retval;
+
+       retval = uart_opal_get(console_sc, &c, 1);
+       if (retval != 1)
+               return (-1);
+#if defined(KDB)
+       kdb_alt_break(c, &alt_break_state);
+#endif
+
+       return (c);
+}
+
+static void
+uart_opal_cnputc(struct consdev *cp, int c)
+{
+       unsigned char ch = c;
+       uart_opal_put(console_sc, &ch, 1);
+}
+
+static void
+uart_opal_cngrab(struct consdev *cp)
+{
+}
+
+static void
+uart_opal_cnungrab(struct consdev *cp)
+{
+}
+
+static void
+uart_opal_ttyoutwakeup(struct tty *tp)
+{
+       struct uart_opal_softc *sc;
+       char buffer[8];
+       int len;
+
+       sc = tty_softc(tp);
+       
+       while ((len = ttydisc_getc(tp, buffer, sizeof(buffer))) != 0)
+               uart_opal_put(sc, buffer, len);
+}
+
+static void
+uart_opal_intr(void *v)
+{
+       struct uart_opal_softc *sc = v;
+       struct tty *tp = sc->tp;
+       unsigned char c;
+       int len;
+
+       tty_lock(tp);
+       while ((len = uart_opal_get(sc, &c, 1)) > 0)
+               ttydisc_rint(tp, c, 0);
+       ttydisc_rint_done(tp);
+       tty_unlock(tp);
+
+       if (sc->irqres == NULL)
+               callout_reset(&sc->callout, sc->polltime, uart_opal_intr, sc);
+}
+

Added: head/sys/powerpc/powernv/opalcall.S
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/powerpc/powernv/opalcall.S Thu Jan 11 07:40:06 2018        
(r327810)
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (C) 2015 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * 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 TOOLS GMBH 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 <machine/asm.h>
+
+GLOBAL(opal_entrypoint)
+       .llong  0
+GLOBAL(opal_data)
+       .llong  0
+GLOBAL(opal_msr)
+       .llong  0
+
+TOC_ENTRY(opal_entrypoint)
+TOC_ENTRY(opal_data)
+TOC_ENTRY(opal_msr)
+
+ASENTRY(opal_call)
+       /* Args:
+        * r3: opal token
+        * r4-r10 opal arguments
+        */
+
+       /* Save call stuff on stack */
+       mflr    %r0
+       std     %r0,16(%r1)
+       std     %r2,-16(%r1)
+       mfcr    %r0
+       std     %r0,8(%r1)
+
+       /* Load OPAL entry information */
+       mr      %r0,%r3
+       ld      %r3,TOC_REF(opal_entrypoint)(%r2)
+       ld      %r3,0(%r3)
+       mtctr   %r3
+
+       /* Save MSR in non-volatile scratch register and turn off translation */
+       std     %r31,-8(%r1)
+       mfmsr   %r31
+
+       /* Load last bits from the TOC */
+       ld      %r3,TOC_REF(opal_msr)(%r2)
+       ld      %r3,0(%r3)
+       ld      %r2,TOC_REF(opal_data)(%r2)
+       ld      %r2,0(%r2)
+
+       mtmsrd  %r3
+       isync
+
+       /* Shift registers over */
+       mr      %r3,%r4
+       mr      %r4,%r5
+       mr      %r5,%r6
+       mr      %r6,%r7
+       mr      %r7,%r8
+       mr      %r8,%r9
+       mr      %r9,%r10
+
+       /* Call OPAL */
+       bctrl
+
+       /* Restore MSR */
+       mtmsrd  %r31
+       isync
+       ld      %r31,-8(%r1)
+       
+       /* Restore call stuff from stack */
+       ld      %r0,16(%r1)
+       mtlr    %r0
+       ld      %r2,-16(%r1)
+       ld      %r0,8(%r1)
+       mtcr    %r0
+
+       /* And return */
+       blr
+

Added: head/sys/powerpc/powernv/platform_powernv.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/powerpc/powernv/platform_powernv.c Thu Jan 11 07:40:06 2018        
(r327810)
@@ -0,0 +1,333 @@
+/*-
+ * Copyright (c) 2015 Nathan Whitehorn
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/smp.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/hid.h>
+#include <machine/platformvar.h>
+#include <machine/pmap.h>
+#include <machine/rtas.h>
+#include <machine/smp.h>
+#include <machine/spr.h>
+#include <machine/trap.h>
+
+#include <dev/ofw/openfirm.h>
+#include <machine/ofw_machdep.h>
+
+#include "platform_if.h"
+#include "opal.h"
+
+#ifdef SMP
+extern void *ap_pcpu;
+#endif
+
+static int powernv_probe(platform_t);
+static int powernv_attach(platform_t);
+void powernv_mem_regions(platform_t, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz);
+static u_long powernv_timebase_freq(platform_t, struct cpuref *cpuref);
+static int powernv_smp_first_cpu(platform_t, struct cpuref *cpuref);
+static int powernv_smp_next_cpu(platform_t, struct cpuref *cpuref);
+static int powernv_smp_get_bsp(platform_t, struct cpuref *cpuref);
+static void powernv_smp_ap_init(platform_t);
+#ifdef SMP
+static int powernv_smp_start_cpu(platform_t, struct pcpu *cpu);
+static struct cpu_group *powernv_smp_topo(platform_t plat);
+#endif
+static void powernv_reset(platform_t);
+
+static platform_method_t powernv_methods[] = {
+       PLATFORMMETHOD(platform_probe,          powernv_probe),
+       PLATFORMMETHOD(platform_attach,         powernv_attach),
+       PLATFORMMETHOD(platform_mem_regions,    powernv_mem_regions),
+       PLATFORMMETHOD(platform_timebase_freq,  powernv_timebase_freq),
+       
+       PLATFORMMETHOD(platform_smp_ap_init,    powernv_smp_ap_init),
+       PLATFORMMETHOD(platform_smp_first_cpu,  powernv_smp_first_cpu),
+       PLATFORMMETHOD(platform_smp_next_cpu,   powernv_smp_next_cpu),
+       PLATFORMMETHOD(platform_smp_get_bsp,    powernv_smp_get_bsp),
+#ifdef SMP
+       PLATFORMMETHOD(platform_smp_start_cpu,  powernv_smp_start_cpu),
+       PLATFORMMETHOD(platform_smp_topo,       powernv_smp_topo),
+#endif
+
+       PLATFORMMETHOD(platform_reset,          powernv_reset),
+
+       { 0, 0 }
+};
+
+static platform_def_t powernv_platform = {
+       "powernv",
+       powernv_methods,
+       0
+};
+
+PLATFORM_DEF(powernv_platform);
+
+static int
+powernv_probe(platform_t plat)
+{
+       if (opal_check() == 0)
+               return (BUS_PROBE_SPECIFIC);
+
+       return (ENXIO);
+}
+
+static int
+powernv_attach(platform_t plat)
+{
+       /* Ping OPAL again just to make sure */
+       opal_check();
+
+       return (0);
+}
+
+void
+powernv_mem_regions(platform_t plat, struct mem_region *phys, int *physsz,
+    struct mem_region *avail, int *availsz)
+{
+
+       ofw_mem_regions(phys, physsz, avail, availsz);
+}
+
+static u_long
+powernv_timebase_freq(platform_t plat, struct cpuref *cpuref)
+{
+       phandle_t phandle;
+       int32_t ticks = -1;
+
+       phandle = cpuref->cr_hwref;
+
+       OF_getprop(phandle, "timebase-frequency", &ticks, sizeof(ticks));
+
+       if (ticks <= 0)
+               panic("Unable to determine timebase frequency!");
+
+       return (ticks);
+}
+
+static int
+powernv_smp_first_cpu(platform_t plat, struct cpuref *cpuref)
+{
+       char buf[8];
+       phandle_t cpu, dev, root;
+       int res, cpuid;
+
+       root = OF_peer(0);
+
+       dev = OF_child(root);
+       while (dev != 0) {
+               res = OF_getprop(dev, "name", buf, sizeof(buf));
+               if (res > 0 && strcmp(buf, "cpus") == 0)
+                       break;
+               dev = OF_peer(dev);
+       }
+       if (dev == 0) {
+               /*
+                * psim doesn't have a name property on the /cpus node,
+                * but it can be found directly
+                */
+               dev = OF_finddevice("/cpus");
+               if (dev == 0)
+                       return (ENOENT);
+       }
+
+       cpu = OF_child(dev);
+
+       while (cpu != 0) {
+               res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
+               if (res > 0 && strcmp(buf, "cpu") == 0)
+                       break;
+               cpu = OF_peer(cpu);
+       }
+       if (cpu == 0)
+               return (ENOENT);
+
+       cpuref->cr_hwref = cpu;
+       res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
+           sizeof(cpuid));
+       if (res <= 0)
+               res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
+       if (res <= 0)
+               cpuid = 0;
+       cpuref->cr_cpuid = cpuid;
+
+       return (0);
+}
+
+static int
+powernv_smp_next_cpu(platform_t plat, struct cpuref *cpuref)
+{
+       char buf[8];
+       phandle_t cpu;
+       int i, res, cpuid;
+
+       /* Check for whether it should be the next thread */
+       res = OF_getproplen(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s");
+       if (res > 0) {
+               cell_t interrupt_servers[res/sizeof(cell_t)];
+               OF_getprop(cpuref->cr_hwref, "ibm,ppc-interrupt-server#s",
+                   interrupt_servers, res);
+               for (i = 0; i < res/sizeof(cell_t) - 1; i++) {
+                       if (interrupt_servers[i] == cpuref->cr_cpuid) {
+                               cpuref->cr_cpuid = interrupt_servers[i+1];
+                               return (0);
+                       }
+               }
+       }
+
+       /* Next CPU core/package */
+       cpu = OF_peer(cpuref->cr_hwref);
+       while (cpu != 0) {
+               res = OF_getprop(cpu, "device_type", buf, sizeof(buf));
+               if (res > 0 && strcmp(buf, "cpu") == 0)
+                       break;
+               cpu = OF_peer(cpu);
+       }
+       if (cpu == 0)
+               return (ENOENT);
+
+       cpuref->cr_hwref = cpu;
+       res = OF_getprop(cpu, "ibm,ppc-interrupt-server#s", &cpuid,
+           sizeof(cpuid));
+       if (res <= 0)
+               res = OF_getprop(cpu, "reg", &cpuid, sizeof(cpuid));
+       if (res <= 0)
+               cpuid = 0;
+       cpuref->cr_cpuid = cpuid;
+
+       return (0);
+}
+
+static int
+powernv_smp_get_bsp(platform_t plat, struct cpuref *cpuref)
+{
+       phandle_t chosen;
+       int cpuid, res;
+       struct cpuref i;
+
+       chosen = OF_finddevice("/chosen");
+       if (chosen == 0)
+               return (ENOENT);
+
+       res = OF_getencprop(chosen, "fdtbootcpu", &cpuid, sizeof(cpuid));
+       if (res < 0)
+               return (ENOENT);
+
+       cpuref->cr_cpuid = cpuid;
+
+       if (powernv_smp_first_cpu(plat, &i) != 0)
+               return (ENOENT);
+       cpuref->cr_hwref = i.cr_hwref;
+
+       do {
+               if (i.cr_cpuid == cpuid) {
+                       cpuref->cr_hwref = i.cr_hwref;
+                       break;
+               }
+       } while (powernv_smp_next_cpu(plat, &i) == 0);
+
+       return (0);
+}
+
+#ifdef SMP
+static int
+powernv_smp_start_cpu(platform_t plat, struct pcpu *pc)
+{
+       int result, err, timeout;
+
+       ap_pcpu = pc;
+       powerpc_sync();
+
+       result = opal_call(OPAL_START_CPU, pc->pc_cpuid, EXC_RST);
+       if (result < 0 || err != 0) {
+               printf("OPAL error (%d/%d): unable to start AP %d\n",
+                   result, err, pc->pc_cpuid);
+               return (ENXIO);
+       }
+
+       timeout = 10000;
+       while (!pc->pc_awake && timeout--)
+               DELAY(100);
+
+       return ((pc->pc_awake) ? 0 : EBUSY);
+}
+
+static struct cpu_group *
+powernv_smp_topo(platform_t plat)
+{
+       struct pcpu *pc, *last_pc;
+       int i, ncores, ncpus;
+
+       ncores = ncpus = 0;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to