1 /* $NetBSD: amdzentemp.c,v 1.7 2018/01/26 23:01:44 pgoyette Exp $ */ 2 /* $OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $ */ 3 4 /* 5 * Copyright (c) 2008 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Christoph Egger. 10 * 11 * NetBSD port by Ian Clark <mrrooster@gmail.com> 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> 37 * 38 * Permission to use, copy, modify, and distribute this software for any 39 * purpose with or without fee is hereby granted, provided that the above 40 * copyright notice and this permission notice appear in all copies. 41 * 42 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 43 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 44 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 45 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 46 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 47 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 48 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 49 */ 50 51 52 #include <sys/cdefs.h> 53 __KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.7 2018/01/26 23:01:44 pgoyette Exp $ "); 54 55 #include <sys/param.h> 56 #include <sys/bus.h> 57 #include <sys/cpu.h> 58 #include <sys/systm.h> 59 #include <sys/device.h> 60 #include <sys/kmem.h> 61 #include <sys/module.h> 62 63 #include <machine/specialreg.h> 64 65 #include <dev/pci/pcireg.h> 66 #include <dev/pci/pcivar.h> 67 #include <dev/pci/pcidevs.h> 68 69 #include <dev/sysmon/sysmonvar.h> 70 71 #include "amdsmn.h" 72 73 /* Address to query for temp on family 17h */ 74 #define AMD_17H_CUR_TMP 0x59800 75 76 struct amdzentemp_softc { 77 pci_chipset_tag_t sc_pc; 78 pcitag_t sc_pcitag; 79 struct sysmon_envsys *sc_sme; 80 device_t sc_smn; 81 envsys_data_t *sc_sensor; 82 size_t sc_sensor_len; 83 size_t sc_numsensors; 84 }; 85 86 87 static int amdzentemp_match(device_t, cfdata_t, void *); 88 static void amdzentemp_attach(device_t, device_t, void *); 89 static int amdzentemp_detach(device_t, int); 90 91 static void amdzentemp_family17_init(struct amdzentemp_softc *); 92 static void amdzentemp_family17_setup_sensors(struct amdzentemp_softc *, int); 93 static void amdzentemp_family17_refresh(struct sysmon_envsys *, envsys_data_t *); 94 95 CFATTACH_DECL_NEW(amdzentemp, sizeof(struct amdzentemp_softc), 96 amdzentemp_match, amdzentemp_attach, amdzentemp_detach, NULL); 97 98 static int 99 amdzentemp_match(device_t parent, cfdata_t match, void *aux) 100 { 101 struct pci_attach_args *pa __diagused = aux; 102 103 KASSERT(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD); 104 105 cfdata_t parent_cfdata = device_cfdata(parent); 106 107 /* Got AMD family 17h system management network */ 108 return parent_cfdata->cf_name && 109 memcmp(parent_cfdata->cf_name, "amdsmn", 6) == 0; 110 } 111 112 static void 113 amdzentemp_attach(device_t parent, device_t self, void *aux) 114 { 115 struct amdzentemp_softc *sc = device_private(self); 116 struct pci_attach_args *pa = aux; 117 int error; 118 size_t i; 119 120 aprint_naive("\n"); 121 aprint_normal(": AMD CPU Temperature Sensors (Family17h)"); 122 123 sc->sc_pc = pa->pa_pc; 124 sc->sc_pcitag = pa->pa_tag; 125 sc->sc_smn = parent; 126 127 amdzentemp_family17_init(sc); 128 129 aprint_normal("\n"); 130 131 sc->sc_sme = sysmon_envsys_create(); 132 sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors; 133 sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP); 134 135 amdzentemp_family17_setup_sensors(sc, device_unit(self)); 136 137 /* 138 * Set properties in sensors. 139 */ 140 for (i = 0; i < sc->sc_numsensors; i++) { 141 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) 142 goto bad; 143 } 144 145 /* 146 * Register the sysmon_envsys device. 147 */ 148 sc->sc_sme->sme_name = device_xname(self); 149 sc->sc_sme->sme_cookie = sc; 150 151 sc->sc_sme->sme_refresh = amdzentemp_family17_refresh; 152 153 error = sysmon_envsys_register(sc->sc_sme); 154 if (error) { 155 aprint_error_dev(self, "unable to register with sysmon " 156 "(error=%d)\n", error); 157 goto bad; 158 } 159 160 (void)pmf_device_register(self, NULL, NULL); 161 162 return; 163 164 bad: 165 if (sc->sc_sme != NULL) { 166 sysmon_envsys_destroy(sc->sc_sme); 167 sc->sc_sme = NULL; 168 } 169 170 kmem_free(sc->sc_sensor, sc->sc_sensor_len); 171 sc->sc_sensor = NULL; 172 } 173 174 static int 175 amdzentemp_detach(device_t self, int flags) 176 { 177 struct amdzentemp_softc *sc = device_private(self); 178 179 pmf_device_deregister(self); 180 if (sc->sc_sme != NULL) 181 sysmon_envsys_unregister(sc->sc_sme); 182 183 if (sc->sc_sensor != NULL) 184 kmem_free(sc->sc_sensor, sc->sc_sensor_len); 185 186 return 0; 187 } 188 189 190 static void 191 amdzentemp_family17_init(struct amdzentemp_softc *sc) 192 { 193 sc->sc_numsensors = 1; 194 } 195 196 static void 197 amdzentemp_family17_setup_sensors(struct amdzentemp_softc *sc, int dv_unit) 198 { 199 sc->sc_sensor[0].units = ENVSYS_STEMP; 200 sc->sc_sensor[0].state = ENVSYS_SVALID; 201 sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY; 202 203 snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc), 204 "cpu%u temperature", dv_unit); 205 } 206 207 static void 208 amdzentemp_family17_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 209 { 210 struct amdzentemp_softc *sc = sme->sme_cookie; 211 uint32_t temp; 212 int error; 213 214 error = amdsmn_read(sc->sc_smn, AMD_17H_CUR_TMP, &temp); 215 if (error) { 216 edata->state = ENVSYS_SINVALID; 217 return; 218 } 219 edata->state = ENVSYS_SVALID; 220 /* From C to uK. */ 221 edata->value_cur = ((temp >> 21) * 125000) + 273150000; 222 } 223 224 MODULE(MODULE_CLASS_DRIVER, amdzentemp, "sysmon_envsys,amdsmn"); 225 226 #ifdef _MODULE 227 #include "ioconf.c" 228 #endif 229 230 static int 231 amdzentemp_modcmd(modcmd_t cmd, void *aux) 232 { 233 int error = 0; 234 235 switch (cmd) { 236 case MODULE_CMD_INIT: 237 #ifdef _MODULE 238 error = config_init_component(cfdriver_ioconf_amdzentemp, 239 cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); 240 #endif 241 return error; 242 case MODULE_CMD_FINI: 243 #ifdef _MODULE 244 error = config_fini_component(cfdriver_ioconf_amdzentemp, 245 cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); 246 #endif 247 return error; 248 default: 249 return ENOTTY; 250 } 251 } 252 253