1 1.4 rin /* $NetBSD: e500wdog.c,v 1.4 2020/07/06 09:34:16 rin Exp $ */ 2 1.2 matt /*- 3 1.2 matt * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. 4 1.2 matt * All rights reserved. 5 1.2 matt * 6 1.2 matt * This code is derived from software contributed to The NetBSD Foundation 7 1.2 matt * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects 8 1.2 matt * Agency and which was developed by Matt Thomas of 3am Software Foundry. 9 1.2 matt * 10 1.2 matt * This material is based upon work supported by the Defense Advanced Research 11 1.2 matt * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under 12 1.2 matt * Contract No. N66001-09-C-2073. 13 1.2 matt * Approved for Public Release, Distribution Unlimited 14 1.2 matt * 15 1.2 matt * Redistribution and use in source and binary forms, with or without 16 1.2 matt * modification, are permitted provided that the following conditions 17 1.2 matt * are met: 18 1.2 matt * 1. Redistributions of source code must retain the above copyright 19 1.2 matt * notice, this list of conditions and the following disclaimer. 20 1.2 matt * 2. Redistributions in binary form must reproduce the above copyright 21 1.2 matt * notice, this list of conditions and the following disclaimer in the 22 1.2 matt * documentation and/or other materials provided with the distribution. 23 1.2 matt * 24 1.2 matt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 1.2 matt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 1.2 matt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 1.2 matt * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 1.2 matt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 1.2 matt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 1.2 matt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 1.2 matt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 1.2 matt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 1.2 matt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 1.2 matt * POSSIBILITY OF SUCH DAMAGE. 35 1.2 matt */ 36 1.2 matt 37 1.2 matt #include <sys/cdefs.h> 38 1.4 rin __KERNEL_RCSID(0, "$NetBSD: e500wdog.c,v 1.4 2020/07/06 09:34:16 rin Exp $"); 39 1.2 matt 40 1.4 rin #include "ioconf.h" 41 1.3 matt 42 1.2 matt #include <sys/param.h> 43 1.2 matt #include <sys/cpu.h> 44 1.2 matt #include <sys/device.h> 45 1.2 matt #include <sys/wdog.h> 46 1.2 matt 47 1.2 matt #include <dev/sysmon/sysmonvar.h> 48 1.2 matt 49 1.2 matt #include <sys/intr.h> 50 1.2 matt 51 1.2 matt #include <powerpc/spr.h> 52 1.2 matt #include <powerpc/booke/spr.h> 53 1.2 matt 54 1.2 matt #include <powerpc/booke/cpuvar.h> 55 1.2 matt 56 1.2 matt struct e500wdog_softc { 57 1.2 matt device_t sc_dev; 58 1.2 matt struct sysmon_wdog sc_smw; 59 1.2 matt u_int sc_wdog_period; 60 1.2 matt bool sc_wdog_armed; 61 1.2 matt uint64_t sc_timebase; 62 1.2 matt }; 63 1.2 matt #ifndef PQ3WDOG_PERIOD_DEFAULT 64 1.2 matt #define PQ3WDOG_PERIOD_DEFAULT 10 65 1.2 matt #endif 66 1.2 matt 67 1.2 matt static int e500wdog_match(device_t, cfdata_t, void *); 68 1.2 matt static void e500wdog_attach(device_t, device_t, void *); 69 1.2 matt 70 1.2 matt CFATTACH_DECL_NEW(e500wdog, sizeof(struct e500wdog_softc), 71 1.2 matt e500wdog_match, e500wdog_attach, NULL, NULL); 72 1.2 matt 73 1.2 matt static int 74 1.2 matt e500wdog_match(device_t parent, cfdata_t cf, void *aux) 75 1.2 matt { 76 1.2 matt struct cpunode_softc * const psc = device_private(parent); 77 1.2 matt struct cpunode_attach_args * const cna = aux; 78 1.2 matt struct cpunode_locators * const cnl = &cna->cna_locs; 79 1.2 matt 80 1.2 matt if (!board_info_get_bool("pq3") 81 1.2 matt || cnl->cnl_instance != 0 82 1.2 matt || (psc->sc_children & cna->cna_childmask) 83 1.2 matt || strcmp(cnl->cnl_name, "wdog") != 0) 84 1.2 matt return 0; 85 1.2 matt 86 1.2 matt return 1; 87 1.2 matt } 88 1.2 matt 89 1.2 matt static int 90 1.2 matt e500wdog_tickle(struct sysmon_wdog *smw) 91 1.2 matt { 92 1.2 matt mtspr(SPR_TSR, TSR_ENW); 93 1.2 matt return 0; 94 1.2 matt } 95 1.2 matt 96 1.2 matt static int 97 1.2 matt e500wdog_setmode(struct sysmon_wdog *smw) 98 1.2 matt { 99 1.2 matt struct e500wdog_softc * const sc = smw->smw_cookie; 100 1.2 matt 101 1.2 matt if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) { 102 1.2 matt /* 103 1.2 matt * We can't disarm the watchdog. 104 1.2 matt */ 105 1.2 matt if (sc->sc_wdog_armed) 106 1.2 matt return EBUSY; 107 1.2 matt } else { 108 1.2 matt /* 109 1.2 matt * If no changes, don't do anything. 110 1.2 matt */ 111 1.2 matt if (sc->sc_wdog_armed 112 1.2 matt && smw->smw_period == sc->sc_wdog_period) { 113 1.2 matt mtspr(SPR_TSR, TSR_ENW); 114 1.2 matt return 0; 115 1.2 matt } 116 1.2 matt printf("%s:%d %u %u\n", __func__, __LINE__, 117 1.2 matt sc->sc_wdog_period, smw->smw_period); 118 1.2 matt if (smw->smw_period == WDOG_PERIOD_DEFAULT) { 119 1.2 matt sc->sc_wdog_period = PQ3WDOG_PERIOD_DEFAULT; 120 1.2 matt smw->smw_period = PQ3WDOG_PERIOD_DEFAULT; 121 1.2 matt } 122 1.2 matt mtspr(SPR_TSR, TSR_ENW); 123 1.2 matt uint32_t tcr = mfspr(SPR_TCR); 124 1.2 matt if (!sc->sc_wdog_armed) 125 1.2 matt tcr = (tcr & ~TCR_WRC) | TCR_WRC_RESET | TCR_WIE; 126 1.2 matt const uint64_t period = sc->sc_wdog_period * sc->sc_timebase / 3; 127 1.2 matt const u_int wp = __builtin_clz(period) + 1; 128 1.2 matt tcr &= ~(TCR_WP|TCR_WPEXT); 129 1.2 matt tcr |= __SHIFTIN(wp, TCR_WP) | __SHIFTIN(wp >> 2, TCR_WPEXT); 130 1.2 matt mtspr(SPR_TCR, tcr); 131 1.2 matt sc->sc_wdog_period = 132 1.2 matt ((1ULL << (63 - wp)) + sc->sc_timebase - 1) 133 1.2 matt / sc->sc_timebase; 134 1.2 matt sc->sc_wdog_armed = true; 135 1.2 matt } 136 1.2 matt return 0; 137 1.2 matt } 138 1.2 matt 139 1.2 matt static void 140 1.2 matt e500wdog_attach(device_t parent, device_t self, void *aux) 141 1.2 matt { 142 1.2 matt struct cpunode_softc * const psc = device_private(parent); 143 1.2 matt struct e500wdog_softc * const sc = device_private(self); 144 1.2 matt struct cpunode_attach_args * const cna = aux; 145 1.2 matt 146 1.2 matt psc->sc_children |= cna->cna_childmask; 147 1.2 matt sc->sc_dev = self; 148 1.2 matt 149 1.2 matt sc->sc_timebase = board_info_get_number("timebase-frequency"); 150 1.2 matt const uint32_t tcr = mfspr(SPR_TCR); 151 1.2 matt u_int wp = __SHIFTOUT(tcr, TCR_WP) | (__SHIFTOUT(tcr, TCR_WPEXT) << 2); 152 1.2 matt 153 1.2 matt #if DEBUG > 1 154 1.2 matt printf(" tcr=%#x wp=%u", tcr, wp); 155 1.2 matt printf(" timebase=%"PRIu64, sc->sc_timebase); 156 1.2 matt #endif 157 1.2 matt sc->sc_wdog_armed = (tcr & TCR_WRC) != 0; 158 1.2 matt if (sc->sc_wdog_armed) 159 1.2 matt sc->sc_wdog_period = ((1ULL << (63 - wp)) + sc->sc_timebase - 1) 160 1.2 matt / sc->sc_timebase; 161 1.2 matt else 162 1.2 matt sc->sc_wdog_period = PQ3WDOG_PERIOD_DEFAULT; 163 1.2 matt 164 1.2 matt aprint_normal(": default period is %u seconds%s\n", 165 1.2 matt sc->sc_wdog_period, 166 1.2 matt sc->sc_wdog_armed ? " (wdog is active)" : ""); 167 1.2 matt 168 1.2 matt sc->sc_smw.smw_name = device_xname(sc->sc_dev); 169 1.2 matt sc->sc_smw.smw_cookie = sc; 170 1.2 matt sc->sc_smw.smw_setmode = e500wdog_setmode; 171 1.2 matt sc->sc_smw.smw_tickle = e500wdog_tickle; 172 1.2 matt sc->sc_smw.smw_period = sc->sc_wdog_period; 173 1.2 matt 174 1.2 matt if (sysmon_wdog_register(&sc->sc_smw) != 0) 175 1.2 matt aprint_error_dev(self, "unable to register with sysmon\n"); 176 1.2 matt 177 1.2 matt #if 1 178 1.2 matt if (sc->sc_wdog_armed) { 179 1.2 matt int error = sysmon_wdog_setmode(&sc->sc_smw, WDOG_MODE_KTICKLE, 180 1.2 matt sc->sc_wdog_period); 181 1.2 matt if (error) 182 1.2 matt aprint_error_dev(self, 183 1.2 matt "failed to start kernel tickler: %d\n", error); 184 1.2 matt } 185 1.2 matt #else 186 1.2 matt //mtspr(SPR_TSR, TSR_ENW); 187 1.2 matt #endif 188 1.2 matt } 189