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