18af4cc4dSJustin Hibbits /*- 28af4cc4dSJustin Hibbits * Copyright (c) 2019 Justin Hibbits 38af4cc4dSJustin Hibbits * 48af4cc4dSJustin Hibbits * Redistribution and use in source and binary forms, with or without 58af4cc4dSJustin Hibbits * modification, are permitted provided that the following conditions 68af4cc4dSJustin Hibbits * are met: 78af4cc4dSJustin Hibbits * 88af4cc4dSJustin Hibbits * 1. Redistributions of source code must retain the above copyright 98af4cc4dSJustin Hibbits * notice, this list of conditions and the following disclaimer. 108af4cc4dSJustin Hibbits * 2. Redistributions in binary form must reproduce the above copyright 118af4cc4dSJustin Hibbits * notice, this list of conditions and the following disclaimer in the 128af4cc4dSJustin Hibbits * documentation and/or other materials provided with the distribution. 138af4cc4dSJustin Hibbits * 148af4cc4dSJustin Hibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 158af4cc4dSJustin Hibbits * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 168af4cc4dSJustin Hibbits * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 178af4cc4dSJustin Hibbits * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 188af4cc4dSJustin Hibbits * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 198af4cc4dSJustin Hibbits * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 208af4cc4dSJustin Hibbits * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 218af4cc4dSJustin Hibbits * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 228af4cc4dSJustin Hibbits * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 238af4cc4dSJustin Hibbits * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 248af4cc4dSJustin Hibbits */ 258af4cc4dSJustin Hibbits 268af4cc4dSJustin Hibbits #include <sys/cdefs.h> 278af4cc4dSJustin Hibbits __FBSDID("$FreeBSD$"); 288af4cc4dSJustin Hibbits 298af4cc4dSJustin Hibbits #include <sys/param.h> 308af4cc4dSJustin Hibbits #include <sys/types.h> 31fdb916d5SJustin Hibbits #include <sys/eventhandler.h> 328af4cc4dSJustin Hibbits #include <sys/kernel.h> 338af4cc4dSJustin Hibbits #include <sys/systm.h> 34fdb916d5SJustin Hibbits #include <sys/endian.h> 358af4cc4dSJustin Hibbits 368af4cc4dSJustin Hibbits #include <vm/vm.h> 378af4cc4dSJustin Hibbits #include <vm/pmap.h> 388af4cc4dSJustin Hibbits 398af4cc4dSJustin Hibbits #include <machine/spr.h> 408af4cc4dSJustin Hibbits #include <machine/trap.h> 418af4cc4dSJustin Hibbits #include "opal.h" 428af4cc4dSJustin Hibbits 43fdb916d5SJustin Hibbits struct opal_hmi_event { 44fdb916d5SJustin Hibbits uint8_t version; 45fdb916d5SJustin Hibbits uint8_t severity; 46fdb916d5SJustin Hibbits uint8_t type; 47fdb916d5SJustin Hibbits uint8_t disposition; 48fdb916d5SJustin Hibbits uint8_t rsvd_1[4]; 49fdb916d5SJustin Hibbits uint64_t hmer; 50fdb916d5SJustin Hibbits uint64_t tfmr; 51fdb916d5SJustin Hibbits union { 52fdb916d5SJustin Hibbits struct { 53fdb916d5SJustin Hibbits uint8_t xstop_type; 54fdb916d5SJustin Hibbits uint8_t rsvd_2[3]; 55fdb916d5SJustin Hibbits uint32_t xstop_reason; 56fdb916d5SJustin Hibbits union { 57fdb916d5SJustin Hibbits uint32_t pir; 58fdb916d5SJustin Hibbits uint32_t chip_id; 59fdb916d5SJustin Hibbits }; 60fdb916d5SJustin Hibbits }; 61fdb916d5SJustin Hibbits }; 62fdb916d5SJustin Hibbits }; 63fdb916d5SJustin Hibbits 64fdb916d5SJustin Hibbits #define HMI_DISP_RECOVERED 0 65fdb916d5SJustin Hibbits #define HMI_DISP_NOT_RECOVERED 1 66fdb916d5SJustin Hibbits 67fdb916d5SJustin Hibbits static void 68fdb916d5SJustin Hibbits opal_hmi_event_handler(void *unused, struct opal_msg *msg) 69fdb916d5SJustin Hibbits { 70fdb916d5SJustin Hibbits struct opal_hmi_event evt; 71fdb916d5SJustin Hibbits 72fdb916d5SJustin Hibbits memcpy(&evt, &msg->params, sizeof(evt)); 73fdb916d5SJustin Hibbits printf("Hypervisor Maintenance Event received" 74fdb916d5SJustin Hibbits "(Severity %d, type %d, HMER: %016lx).\n", 75fdb916d5SJustin Hibbits evt.severity, evt.type, evt.hmer); 76fdb916d5SJustin Hibbits 77fdb916d5SJustin Hibbits if (evt.disposition == HMI_DISP_NOT_RECOVERED) 78fdb916d5SJustin Hibbits panic("Unrecoverable hypervisor maintenance exception on CPU %d", 79fdb916d5SJustin Hibbits evt.pir); 80fdb916d5SJustin Hibbits 81fdb916d5SJustin Hibbits return; 82fdb916d5SJustin Hibbits } 83fdb916d5SJustin Hibbits 848af4cc4dSJustin Hibbits static int 851c56203bSJustin Hibbits opal_hmi_handler2(struct trapframe *frame) 861c56203bSJustin Hibbits { 879367fb30SBrandon Bergren /* 889367fb30SBrandon Bergren * Use DMAP preallocated pcpu memory to handle 899367fb30SBrandon Bergren * the phys flags pointer. 909367fb30SBrandon Bergren */ 919367fb30SBrandon Bergren uint64_t *flags = PCPU_PTR(aim.opal_hmi_flags); 921c56203bSJustin Hibbits int err; 931c56203bSJustin Hibbits 949367fb30SBrandon Bergren *flags = 0; 959367fb30SBrandon Bergren err = opal_call(OPAL_HANDLE_HMI2, DMAP_TO_PHYS((vm_offset_t)flags)); 961c56203bSJustin Hibbits 97*05c3051fSBrandon Bergren if (be64toh(*flags) & OPAL_HMI_FLAGS_TOD_TB_FAIL) 981c56203bSJustin Hibbits panic("TOD/TB recovery failure"); 991c56203bSJustin Hibbits 1001c56203bSJustin Hibbits if (err == OPAL_SUCCESS) 1011c56203bSJustin Hibbits return (0); 1021c56203bSJustin Hibbits 1031c56203bSJustin Hibbits printf("HMI handler failed! OPAL error code: %d\n", err); 1041c56203bSJustin Hibbits 1051c56203bSJustin Hibbits return (-1); 1061c56203bSJustin Hibbits } 1071c56203bSJustin Hibbits 1081c56203bSJustin Hibbits static int 1098af4cc4dSJustin Hibbits opal_hmi_handler(struct trapframe *frame) 1108af4cc4dSJustin Hibbits { 1118af4cc4dSJustin Hibbits int err; 1128af4cc4dSJustin Hibbits 1138af4cc4dSJustin Hibbits err = opal_call(OPAL_HANDLE_HMI); 1148af4cc4dSJustin Hibbits 1151c56203bSJustin Hibbits if (err == OPAL_SUCCESS) 1168af4cc4dSJustin Hibbits return (0); 1178af4cc4dSJustin Hibbits 1188af4cc4dSJustin Hibbits printf("HMI handler failed! OPAL error code: %d\n", err); 1198af4cc4dSJustin Hibbits 1208af4cc4dSJustin Hibbits return (-1); 1218af4cc4dSJustin Hibbits } 1228af4cc4dSJustin Hibbits 1238af4cc4dSJustin Hibbits static void 1248af4cc4dSJustin Hibbits opal_setup_hmi(void *data) 1258af4cc4dSJustin Hibbits { 1268af4cc4dSJustin Hibbits /* This only works for OPAL, so first make sure we have it. */ 1278af4cc4dSJustin Hibbits if (opal_check() != 0) 1288af4cc4dSJustin Hibbits return; 1298af4cc4dSJustin Hibbits 1301c56203bSJustin Hibbits if (opal_call(OPAL_CHECK_TOKEN, OPAL_HANDLE_HMI2) == OPAL_TOKEN_PRESENT) 1311c56203bSJustin Hibbits hmi_handler = opal_hmi_handler2; 1321c56203bSJustin Hibbits else if (opal_call(OPAL_CHECK_TOKEN, OPAL_HANDLE_HMI) == OPAL_TOKEN_PRESENT) 1338af4cc4dSJustin Hibbits hmi_handler = opal_hmi_handler; 1348af4cc4dSJustin Hibbits else { 1358af4cc4dSJustin Hibbits printf("Warning: No OPAL HMI handler found.\n"); 1368af4cc4dSJustin Hibbits return; 1378af4cc4dSJustin Hibbits } 1388af4cc4dSJustin Hibbits 139fdb916d5SJustin Hibbits EVENTHANDLER_REGISTER(OPAL_HMI_EVT, opal_hmi_event_handler, NULL, 140fdb916d5SJustin Hibbits EVENTHANDLER_PRI_ANY); 141fdb916d5SJustin Hibbits 1428af4cc4dSJustin Hibbits if (bootverbose) 1438af4cc4dSJustin Hibbits printf("Installed OPAL HMI handler.\n"); 1448af4cc4dSJustin Hibbits } 1458af4cc4dSJustin Hibbits 146fdb916d5SJustin Hibbits SYSINIT(opal_setup_hmi, SI_SUB_CPU, SI_ORDER_ANY, opal_setup_hmi, NULL); 147