| @@ -1,498 +1,502 @@ | | | @@ -1,498 +1,502 @@ |
1 | /* $NetBSD: amdzentemp.c,v 1.19 2023/07/28 00:11:15 msaitoh Exp $ */ | | 1 | /* $NetBSD: amdzentemp.c,v 1.20 2023/07/28 02:05:26 msaitoh Exp $ */ |
2 | /* $OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $ */ | | 2 | /* $OpenBSD: kate.c,v 1.2 2008/03/27 04:52:03 cnst Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc. | | 5 | * Copyright (c) 2008, 2020 The NetBSD Foundation, Inc. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * Copyright (c) 2019 Conrad Meyer <cem@FreeBSD.org> | | 8 | * Copyright (c) 2019 Conrad Meyer <cem@FreeBSD.org> |
9 | * All rights reserved. | | 9 | * All rights reserved. |
10 | * | | 10 | * |
11 | * This code is derived from software contributed to The NetBSD Foundation | | 11 | * This code is derived from software contributed to The NetBSD Foundation |
12 | * by Christoph Egger. | | 12 | * by Christoph Egger. |
13 | * | | 13 | * |
14 | * NetBSD port by Ian Clark <mrrooster@gmail.com> | | 14 | * NetBSD port by Ian Clark <mrrooster@gmail.com> |
15 | * | | 15 | * |
16 | * Redistribution and use in source and binary forms, with or without | | 16 | * Redistribution and use in source and binary forms, with or without |
17 | * modification, are permitted provided that the following conditions | | 17 | * modification, are permitted provided that the following conditions |
18 | * are met: | | 18 | * are met: |
19 | * 1. Redistributions of source code must retain the above copyright | | 19 | * 1. Redistributions of source code must retain the above copyright |
20 | * notice, this list of conditions and the following disclaimer. | | 20 | * notice, this list of conditions and the following disclaimer. |
21 | * 2. Redistributions in binary form must reproduce the above copyright | | 21 | * 2. Redistributions in binary form must reproduce the above copyright |
22 | * notice, this list of conditions and the following disclaimer in the | | 22 | * notice, this list of conditions and the following disclaimer in the |
23 | * documentation and/or other materials provided with the distribution. | | 23 | * documentation and/or other materials provided with the distribution. |
24 | * | | 24 | * |
25 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 25 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
26 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 26 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 27 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 28 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 29 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 30 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 31 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 32 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 33 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 34 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
35 | * POSSIBILITY OF SUCH DAMAGE. | | 35 | * POSSIBILITY OF SUCH DAMAGE. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | /* | | 38 | /* |
39 | * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> | | 39 | * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> |
40 | * | | 40 | * |
41 | * Permission to use, copy, modify, and distribute this software for any | | 41 | * Permission to use, copy, modify, and distribute this software for any |
42 | * purpose with or without fee is hereby granted, provided that the above | | 42 | * purpose with or without fee is hereby granted, provided that the above |
43 | * copyright notice and this permission notice appear in all copies. | | 43 | * copyright notice and this permission notice appear in all copies. |
44 | * | | 44 | * |
45 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 45 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
46 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 46 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
47 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 47 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
48 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 48 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
49 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 49 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
50 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 50 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
51 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 51 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
52 | */ | | 52 | */ |
53 | | | 53 | |
54 | | | 54 | |
55 | #include <sys/cdefs.h> | | 55 | #include <sys/cdefs.h> |
56 | __KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.19 2023/07/28 00:11:15 msaitoh Exp $ "); | | 56 | __KERNEL_RCSID(0, "$NetBSD: amdzentemp.c,v 1.20 2023/07/28 02:05:26 msaitoh Exp $ "); |
57 | | | 57 | |
58 | #include <sys/param.h> | | 58 | #include <sys/param.h> |
59 | #include <sys/bus.h> | | 59 | #include <sys/bus.h> |
60 | #include <sys/cpu.h> | | 60 | #include <sys/cpu.h> |
61 | #include <sys/systm.h> | | 61 | #include <sys/systm.h> |
62 | #include <sys/device.h> | | 62 | #include <sys/device.h> |
63 | #include <sys/kmem.h> | | 63 | #include <sys/kmem.h> |
64 | #include <sys/module.h> | | 64 | #include <sys/module.h> |
65 | | | 65 | |
66 | #include <machine/specialreg.h> | | 66 | #include <machine/specialreg.h> |
67 | | | 67 | |
68 | #include <dev/pci/pcireg.h> | | 68 | #include <dev/pci/pcireg.h> |
69 | #include <dev/pci/pcivar.h> | | 69 | #include <dev/pci/pcivar.h> |
70 | #include <dev/pci/pcidevs.h> | | 70 | #include <dev/pci/pcidevs.h> |
71 | | | 71 | |
72 | #include <dev/sysmon/sysmonvar.h> | | 72 | #include <dev/sysmon/sysmonvar.h> |
73 | | | 73 | |
74 | #include "amdsmn.h" | | 74 | #include "amdsmn.h" |
75 | | | 75 | |
76 | #define AMD_CURTMP_RANGE_ADJUST 49000000 /* in microKelvins (ie, 49C) */ | | 76 | #define AMD_CURTMP_RANGE_ADJUST 49000000 /* in microKelvins (ie, 49C) */ |
77 | #define F10_TEMP_CURTMP __BITS(31,21) /* XXX same as amdtemp.c */ | | 77 | #define F10_TEMP_CURTMP __BITS(31,21) /* XXX same as amdtemp.c */ |
78 | #define F10_TEMP_CURTMP_MASK 0x7ff | | 78 | #define F10_TEMP_CURTMP_MASK 0x7ff |
79 | #define F15M60_CURTMP_TJSEL __BITS(17,16) | | 79 | #define F15M60_CURTMP_TJSEL __BITS(17,16) |
80 | | | 80 | |
81 | /* | | 81 | /* |
82 | * Reported Temperature, Family 15h, M60+ | | 82 | * Reported Temperature, Family 15h, M60+ |
83 | * | | 83 | * |
84 | * Same register bit definitions as other Family 15h CPUs, but access is | | 84 | * Same register bit definitions as other Family 15h CPUs, but access is |
85 | * indirect via SMN, like Family 17h. | | 85 | * indirect via SMN, like Family 17h. |
86 | */ | | 86 | */ |
87 | #define AMD_15H_M60H_REPTMP_CTRL 0xd8200ca4 | | 87 | #define AMD_15H_M60H_REPTMP_CTRL 0xd8200ca4 |
88 | | | 88 | |
89 | /* | | 89 | /* |
90 | * Reported Temperature, Family 17h | | 90 | * Reported Temperature, Family 17h |
91 | * | | 91 | * |
92 | * According to AMD OSRR for 17H, section 4.2.1, bits 31-21 of this register | | 92 | * According to AMD OSRR for 17H, section 4.2.1, bits 31-21 of this register |
93 | * provide the current temp. bit 19, when clear, means the temp is reported in | | 93 | * provide the current temp. bit 19, when clear, means the temp is reported in |
94 | * a range 0.."225C" (probable typo for 255C), and when set changes the range | | 94 | * a range 0.."225C" (probable typo for 255C), and when set changes the range |
95 | * to -49..206C. | | 95 | * to -49..206C. |
96 | */ | | 96 | */ |
97 | #define AMD_17H_CUR_TMP 0x59800 | | 97 | #define AMD_17H_CUR_TMP 0x59800 |
98 | #define AMD_17H_CUR_TMP_RANGE_SEL __BIT(19) | | 98 | #define AMD_17H_CUR_TMP_RANGE_SEL __BIT(19) |
99 | #define AMD_17H_CCD_TMP_VALID __BIT(11) | | 99 | #define AMD_17H_CCD_TMP_VALID __BIT(11) |
100 | | | 100 | |
101 | struct amdzentemp_softc { | | 101 | struct amdzentemp_softc { |
102 | device_t sc_dev; | | 102 | device_t sc_dev; |
103 | struct sysmon_envsys *sc_sme; | | 103 | struct sysmon_envsys *sc_sme; |
104 | device_t sc_smn; | | 104 | device_t sc_smn; |
105 | envsys_data_t *sc_sensor; | | 105 | envsys_data_t *sc_sensor; |
106 | size_t sc_sensor_len; | | 106 | size_t sc_sensor_len; |
107 | size_t sc_numsensors; | | 107 | size_t sc_numsensors; |
108 | int32_t sc_offset; | | 108 | int32_t sc_offset; |
109 | int32_t sc_ccd_offset; | | 109 | int32_t sc_ccd_offset; |
110 | }; | | 110 | }; |
111 | | | 111 | |
112 | enum { | | 112 | enum { |
113 | NOSENSOR = 0, | | 113 | NOSENSOR = 0, |
114 | CORE0_SENSOR0, | | 114 | CORE0_SENSOR0, |
115 | CCD_BASE, | | 115 | CCD_BASE, |
116 | CCD0 = CCD_BASE, | | 116 | CCD0 = CCD_BASE, |
117 | CCD1, | | 117 | CCD1, |
118 | CCD2, | | 118 | CCD2, |
119 | CCD3, | | 119 | CCD3, |
120 | CCD4, | | 120 | CCD4, |
121 | CCD5, | | 121 | CCD5, |
122 | CCD6, | | 122 | CCD6, |
123 | CCD7, | | 123 | CCD7, |
124 | CCD8, | | 124 | CCD8, |
125 | CCD9, | | 125 | CCD9, |
126 | CCD10, | | 126 | CCD10, |
127 | CCD11, | | 127 | CCD11, |
128 | CCD_MAX, | | 128 | CCD_MAX, |
129 | NUM_CCDS = CCD_MAX - CCD_BASE | | 129 | NUM_CCDS = CCD_MAX - CCD_BASE |
130 | }; | | 130 | }; |
131 | | | 131 | |
132 | | | 132 | |
133 | static int amdzentemp_match(device_t, cfdata_t, void *); | | 133 | static int amdzentemp_match(device_t, cfdata_t, void *); |
134 | static void amdzentemp_attach(device_t, device_t, void *); | | 134 | static void amdzentemp_attach(device_t, device_t, void *); |
135 | static int amdzentemp_detach(device_t, int); | | 135 | static int amdzentemp_detach(device_t, int); |
136 | | | 136 | |
137 | static void amdzentemp_init(struct amdzentemp_softc *, int, int); | | 137 | static void amdzentemp_init(struct amdzentemp_softc *, int, int); |
138 | static void amdzentemp_setup_sensors(struct amdzentemp_softc *); | | 138 | static void amdzentemp_setup_sensors(struct amdzentemp_softc *); |
139 | static void amdzentemp_family15_refresh(struct sysmon_envsys *, envsys_data_t *); | | 139 | static void amdzentemp_family15_refresh(struct sysmon_envsys *, envsys_data_t *); |
140 | static void amdzentemp_family17_refresh(struct sysmon_envsys *, envsys_data_t *); | | 140 | static void amdzentemp_family17_refresh(struct sysmon_envsys *, envsys_data_t *); |
141 | static int amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *, int, int); | | 141 | static int amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *, int, int); |
142 | static void amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *); | | 142 | static void amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *); |
143 | | | 143 | |
144 | CFATTACH_DECL_NEW(amdzentemp, sizeof(struct amdzentemp_softc), | | 144 | CFATTACH_DECL_NEW(amdzentemp, sizeof(struct amdzentemp_softc), |
145 | amdzentemp_match, amdzentemp_attach, amdzentemp_detach, NULL); | | 145 | amdzentemp_match, amdzentemp_attach, amdzentemp_detach, NULL); |
146 | | | 146 | |
147 | static int | | 147 | static int |
148 | amdzentemp_match(device_t parent, cfdata_t match, void *aux) | | 148 | amdzentemp_match(device_t parent, cfdata_t match, void *aux) |
149 | { | | 149 | { |
150 | struct pci_attach_args *pa __diagused = aux; | | 150 | struct pci_attach_args *pa __diagused = aux; |
151 | | | 151 | |
152 | KASSERT(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD); | | 152 | KASSERT(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD); |
153 | | | 153 | |
154 | cfdata_t parent_cfdata = device_cfdata(parent); | | 154 | cfdata_t parent_cfdata = device_cfdata(parent); |
155 | | | 155 | |
156 | /* Got AMD family 17h system management network */ | | 156 | /* Got AMD family 17h system management network */ |
157 | return parent_cfdata->cf_name && | | 157 | return parent_cfdata->cf_name && |
158 | memcmp(parent_cfdata->cf_name, "amdsmn", 6) == 0; | | 158 | memcmp(parent_cfdata->cf_name, "amdsmn", 6) == 0; |
159 | } | | 159 | } |
160 | | | 160 | |
161 | static void | | 161 | static void |
162 | amdzentemp_attach(device_t parent, device_t self, void *aux) | | 162 | amdzentemp_attach(device_t parent, device_t self, void *aux) |
163 | { | | 163 | { |
164 | struct amdzentemp_softc *sc = device_private(self); | | 164 | struct amdzentemp_softc *sc = device_private(self); |
165 | struct cpu_info *ci = curcpu(); | | 165 | struct cpu_info *ci = curcpu(); |
166 | int family, model; | | 166 | int family, model; |
167 | int error; | | 167 | int error; |
168 | size_t i; | | 168 | size_t i; |
169 | | | 169 | |
170 | sc->sc_dev = self; | | 170 | sc->sc_dev = self; |
171 | | | 171 | |
172 | family = CPUID_TO_FAMILY(ci->ci_signature); | | 172 | family = CPUID_TO_FAMILY(ci->ci_signature); |
173 | model = CPUID_TO_MODEL(ci->ci_signature); | | 173 | model = CPUID_TO_MODEL(ci->ci_signature); |
174 | aprint_naive("\n"); | | 174 | aprint_naive("\n"); |
175 | aprint_normal(": AMD CPU Temperature Sensors (Family%xh)", family); | | 175 | aprint_normal(": AMD CPU Temperature Sensors (Family%xh)", family); |
176 | | | 176 | |
177 | sc->sc_smn = parent; | | 177 | sc->sc_smn = parent; |
178 | | | 178 | |
179 | amdzentemp_init(sc, family, model); | | 179 | amdzentemp_init(sc, family, model); |
180 | | | 180 | |
181 | aprint_normal("\n"); | | 181 | aprint_normal("\n"); |
182 | | | 182 | |
183 | sc->sc_sme = sysmon_envsys_create(); | | 183 | sc->sc_sme = sysmon_envsys_create(); |
184 | sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors; | | 184 | sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors; |
185 | sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP); | | 185 | sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP); |
186 | | | 186 | |
187 | amdzentemp_setup_sensors(sc); | | 187 | amdzentemp_setup_sensors(sc); |
188 | | | 188 | |
189 | /* | | 189 | /* |
190 | * Set properties in sensors. | | 190 | * Set properties in sensors. |
191 | */ | | 191 | */ |
192 | for (i = 0; i < sc->sc_numsensors; i++) { | | 192 | for (i = 0; i < sc->sc_numsensors; i++) { |
193 | if (sc->sc_sensor[i].private == NOSENSOR) | | 193 | if (sc->sc_sensor[i].private == NOSENSOR) |
194 | continue; | | 194 | continue; |
195 | if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) | | 195 | if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[i])) |
196 | goto bad; | | 196 | goto bad; |
197 | } | | 197 | } |
198 | | | 198 | |
199 | /* | | 199 | /* |
200 | * Register the sysmon_envsys device. | | 200 | * Register the sysmon_envsys device. |
201 | */ | | 201 | */ |
202 | sc->sc_sme->sme_name = device_xname(self); | | 202 | sc->sc_sme->sme_name = device_xname(self); |
203 | sc->sc_sme->sme_cookie = sc; | | 203 | sc->sc_sme->sme_cookie = sc; |
204 | | | 204 | |
205 | switch (family) { | | 205 | switch (family) { |
206 | case 0x15: | | 206 | case 0x15: |
207 | sc->sc_sme->sme_refresh = amdzentemp_family15_refresh; | | 207 | sc->sc_sme->sme_refresh = amdzentemp_family15_refresh; |
208 | break; | | 208 | break; |
209 | case 0x17: | | 209 | case 0x17: |
210 | case 0x19: | | 210 | case 0x19: |
211 | sc->sc_sme->sme_refresh = amdzentemp_family17_refresh; | | 211 | sc->sc_sme->sme_refresh = amdzentemp_family17_refresh; |
212 | break; | | 212 | break; |
213 | default: | | 213 | default: |
214 | /* XXX panic */ | | 214 | /* XXX panic */ |
215 | break; | | 215 | break; |
216 | } | | 216 | } |
217 | | | 217 | |
218 | error = sysmon_envsys_register(sc->sc_sme); | | 218 | error = sysmon_envsys_register(sc->sc_sme); |
219 | if (error) { | | 219 | if (error) { |
220 | aprint_error_dev(self, "unable to register with sysmon " | | 220 | aprint_error_dev(self, "unable to register with sysmon " |
221 | "(error=%d)\n", error); | | 221 | "(error=%d)\n", error); |
222 | goto bad; | | 222 | goto bad; |
223 | } | | 223 | } |
224 | | | 224 | |
225 | (void)pmf_device_register(self, NULL, NULL); | | 225 | (void)pmf_device_register(self, NULL, NULL); |
226 | | | 226 | |
227 | return; | | 227 | return; |
228 | | | 228 | |
229 | bad: | | 229 | bad: |
230 | if (sc->sc_sme != NULL) { | | 230 | if (sc->sc_sme != NULL) { |
231 | sysmon_envsys_destroy(sc->sc_sme); | | 231 | sysmon_envsys_destroy(sc->sc_sme); |
232 | sc->sc_sme = NULL; | | 232 | sc->sc_sme = NULL; |
233 | } | | 233 | } |
234 | | | 234 | |
235 | kmem_free(sc->sc_sensor, sc->sc_sensor_len); | | 235 | kmem_free(sc->sc_sensor, sc->sc_sensor_len); |
236 | sc->sc_sensor = NULL; | | 236 | sc->sc_sensor = NULL; |
237 | } | | 237 | } |
238 | | | 238 | |
239 | static int | | 239 | static int |
240 | amdzentemp_detach(device_t self, int flags) | | 240 | amdzentemp_detach(device_t self, int flags) |
241 | { | | 241 | { |
242 | struct amdzentemp_softc *sc = device_private(self); | | 242 | struct amdzentemp_softc *sc = device_private(self); |
243 | | | 243 | |
244 | pmf_device_deregister(self); | | 244 | pmf_device_deregister(self); |
245 | if (sc->sc_sme != NULL) | | 245 | if (sc->sc_sme != NULL) |
246 | sysmon_envsys_unregister(sc->sc_sme); | | 246 | sysmon_envsys_unregister(sc->sc_sme); |
247 | | | 247 | |
248 | if (sc->sc_sensor != NULL) | | 248 | if (sc->sc_sensor != NULL) |
249 | kmem_free(sc->sc_sensor, sc->sc_sensor_len); | | 249 | kmem_free(sc->sc_sensor, sc->sc_sensor_len); |
250 | | | 250 | |
251 | return 0; | | 251 | return 0; |
252 | } | | 252 | } |
253 | | | 253 | |
254 | | | 254 | |
255 | static void | | 255 | static void |
256 | amdzentemp_init(struct amdzentemp_softc *sc, int family, int model) | | 256 | amdzentemp_init(struct amdzentemp_softc *sc, int family, int model) |
257 | { | | 257 | { |
258 | | | 258 | |
259 | sc->sc_numsensors = 1 + amdzentemp_probe_ccd_sensors(sc, family, model); | | 259 | sc->sc_numsensors = 1 + amdzentemp_probe_ccd_sensors(sc, family, model); |
260 | sc->sc_offset = 0; | | 260 | sc->sc_offset = 0; |
261 | | | 261 | |
262 | if (strstr(cpu_brand_string, "AMD Ryzen 5 1600X") | | 262 | if (strstr(cpu_brand_string, "AMD Ryzen 5 1600X") |
263 | || strstr(cpu_brand_string, "AMD Ryzen 7 1700X") | | 263 | || strstr(cpu_brand_string, "AMD Ryzen 7 1700X") |
264 | || strstr(cpu_brand_string, "AMD Ryzen 7 1800X")) | | 264 | || strstr(cpu_brand_string, "AMD Ryzen 7 1800X")) |
265 | sc->sc_offset = -20000000; | | 265 | sc->sc_offset = -20000000; |
266 | else if (strstr(cpu_brand_string, "AMD Ryzen 7 2700X")) | | 266 | else if (strstr(cpu_brand_string, "AMD Ryzen 7 2700X")) |
267 | sc->sc_offset = -10000000; | | 267 | sc->sc_offset = -10000000; |
268 | else if (strstr(cpu_brand_string, "AMD Ryzen Threadripper 19") | | 268 | else if (strstr(cpu_brand_string, "AMD Ryzen Threadripper 19") |
269 | || strstr(cpu_brand_string, "AMD Ryzen Threadripper 29")) | | 269 | || strstr(cpu_brand_string, "AMD Ryzen Threadripper 29")) |
270 | sc->sc_offset = -27000000; | | 270 | sc->sc_offset = -27000000; |
271 | } | | 271 | } |
272 | | | 272 | |
273 | static void | | 273 | static void |
274 | amdzentemp_setup_sensors(struct amdzentemp_softc *sc) | | 274 | amdzentemp_setup_sensors(struct amdzentemp_softc *sc) |
275 | { | | 275 | { |
276 | sc->sc_sensor[0].units = ENVSYS_STEMP; | | 276 | sc->sc_sensor[0].units = ENVSYS_STEMP; |
277 | sc->sc_sensor[0].state = ENVSYS_SVALID; | | 277 | sc->sc_sensor[0].state = ENVSYS_SVALID; |
278 | sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY; | | 278 | sc->sc_sensor[0].flags = ENVSYS_FHAS_ENTROPY; |
279 | sc->sc_sensor[0].private = CORE0_SENSOR0; | | 279 | sc->sc_sensor[0].private = CORE0_SENSOR0; |
280 | | | 280 | |
281 | snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc), | | 281 | snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc), |
282 | "cpu%u temperature", device_unit(sc->sc_dev)); | | 282 | "cpu%u temperature", device_unit(sc->sc_dev)); |
283 | | | 283 | |
284 | if (sc->sc_numsensors > 1) | | 284 | if (sc->sc_numsensors > 1) |
285 | amdzentemp_setup_ccd_sensors(sc); | | 285 | amdzentemp_setup_ccd_sensors(sc); |
286 | } | | 286 | } |
287 | | | 287 | |
288 | static void | | 288 | static void |
289 | amdzentemp_family15_refresh(struct sysmon_envsys *sme, | | 289 | amdzentemp_family15_refresh(struct sysmon_envsys *sme, |
290 | envsys_data_t *edata) | | 290 | envsys_data_t *edata) |
291 | { | | 291 | { |
292 | struct amdzentemp_softc *sc = sme->sme_cookie; | | 292 | struct amdzentemp_softc *sc = sme->sme_cookie; |
293 | uint32_t val, temp; | | 293 | uint32_t val, temp; |
294 | int error; | | 294 | int error; |
295 | | | 295 | |
296 | error = amdsmn_read(sc->sc_smn, AMD_15H_M60H_REPTMP_CTRL, &val); | | 296 | error = amdsmn_read(sc->sc_smn, AMD_15H_M60H_REPTMP_CTRL, &val); |
297 | if (error) { | | 297 | if (error) { |
298 | edata->state = ENVSYS_SINVALID; | | 298 | edata->state = ENVSYS_SINVALID; |
299 | return; | | 299 | return; |
300 | } | | 300 | } |
301 | | | 301 | |
302 | /* from amdtemp.c:amdtemp_family10_refresh() */ | | 302 | /* from amdtemp.c:amdtemp_family10_refresh() */ |
303 | temp = __SHIFTOUT(val, F10_TEMP_CURTMP); | | 303 | temp = __SHIFTOUT(val, F10_TEMP_CURTMP); |
304 | | | 304 | |
305 | /* From Celsius to micro-Kelvin. */ | | 305 | /* From Celsius to micro-Kelvin. */ |
306 | edata->value_cur = (temp * 125000) + 273150000; | | 306 | edata->value_cur = (temp * 125000) + 273150000; |
307 | | | 307 | |
308 | /* | | 308 | /* |
309 | * On Family 15h and higher, if CurTmpTjSel is 11b, the range is | | 309 | * On Family 15h and higher, if CurTmpTjSel is 11b, the range is |
310 | * adjusted down by 49.0 degrees Celsius. (This adjustment is not | | 310 | * adjusted down by 49.0 degrees Celsius. (This adjustment is not |
311 | * documented in BKDGs prior to family 15h model 00h.) | | 311 | * documented in BKDGs prior to family 15h model 00h.) |
312 | * | | 312 | * |
313 | * XXX should be in amdtemp.c:amdtemp_family10_refresh() for f15 | | 313 | * XXX should be in amdtemp.c:amdtemp_family10_refresh() for f15 |
314 | * as well?? | | 314 | * as well?? |
315 | */ | | 315 | */ |
316 | if (__SHIFTOUT(val, F15M60_CURTMP_TJSEL) == 0x3) | | 316 | if (__SHIFTOUT(val, F15M60_CURTMP_TJSEL) == 0x3) |
317 | edata->value_cur -= AMD_CURTMP_RANGE_ADJUST; | | 317 | edata->value_cur -= AMD_CURTMP_RANGE_ADJUST; |
318 | | | 318 | |
319 | edata->state = ENVSYS_SVALID; | | 319 | edata->state = ENVSYS_SVALID; |
320 | } | | 320 | } |
321 | | | 321 | |
322 | static void | | 322 | static void |
323 | amdzentemp_family17_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 323 | amdzentemp_family17_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
324 | { | | 324 | { |
325 | struct amdzentemp_softc *sc = sme->sme_cookie; | | 325 | struct amdzentemp_softc *sc = sme->sme_cookie; |
326 | uint32_t temp; | | 326 | uint32_t temp; |
327 | bool minus49; | | 327 | bool minus49; |
328 | int i, error; | | 328 | int i, error; |
329 | | | 329 | |
330 | switch (edata->private) { | | 330 | switch (edata->private) { |
331 | case CORE0_SENSOR0: | | 331 | case CORE0_SENSOR0: |
332 | /* Tctl */ | | 332 | /* Tctl */ |
333 | error = amdsmn_read(sc->sc_smn, AMD_17H_CUR_TMP, &temp); | | 333 | error = amdsmn_read(sc->sc_smn, AMD_17H_CUR_TMP, &temp); |
334 | if (error) { | | 334 | if (error) { |
335 | edata->state = ENVSYS_SINVALID; | | 335 | edata->state = ENVSYS_SINVALID; |
336 | return; | | 336 | return; |
337 | } | | 337 | } |
338 | minus49 = (temp & AMD_17H_CUR_TMP_RANGE_SEL) ? | | 338 | minus49 = (temp & AMD_17H_CUR_TMP_RANGE_SEL) ? |
339 | true : false; | | 339 | true : false; |
340 | temp = __SHIFTOUT(temp, F10_TEMP_CURTMP); | | 340 | temp = __SHIFTOUT(temp, F10_TEMP_CURTMP); |
341 | break; | | 341 | break; |
342 | case CCD_BASE ... (CCD_MAX - 1): | | 342 | case CCD_BASE ... (CCD_MAX - 1): |
343 | /* Tccd */ | | 343 | /* Tccd */ |
344 | i = edata->private - CCD_BASE; | | 344 | i = edata->private - CCD_BASE; |
345 | error = amdsmn_read(sc->sc_smn, | | 345 | error = amdsmn_read(sc->sc_smn, |
346 | AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)), | | 346 | AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)), |
347 | &temp); | | 347 | &temp); |
348 | if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) { | | 348 | if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) { |
349 | edata->state = ENVSYS_SINVALID; | | 349 | edata->state = ENVSYS_SINVALID; |
350 | return; | | 350 | return; |
351 | } | | 351 | } |
352 | minus49 = true; | | 352 | minus49 = true; |
353 | temp &= F10_TEMP_CURTMP_MASK; | | 353 | temp &= F10_TEMP_CURTMP_MASK; |
354 | break; | | 354 | break; |
355 | default: | | 355 | default: |
356 | edata->state = ENVSYS_SINVALID; | | 356 | edata->state = ENVSYS_SINVALID; |
357 | return; | | 357 | return; |
358 | } | | 358 | } |
359 | edata->state = ENVSYS_SVALID; | | 359 | edata->state = ENVSYS_SVALID; |
360 | /* From C to uK. */ | | 360 | /* From C to uK. */ |
361 | edata->value_cur = (temp * 125000) + 273150000; | | 361 | edata->value_cur = (temp * 125000) + 273150000; |
362 | /* adjust for possible offset of 49K */ | | 362 | /* adjust for possible offset of 49K */ |
363 | if (minus49) | | 363 | if (minus49) |
364 | edata->value_cur -= AMD_CURTMP_RANGE_ADJUST; | | 364 | edata->value_cur -= AMD_CURTMP_RANGE_ADJUST; |
365 | edata->value_cur += sc->sc_offset; | | 365 | edata->value_cur += sc->sc_offset; |
366 | } | | 366 | } |
367 | | | 367 | |
368 | static int | | 368 | static int |
369 | amdzentemp_probe_ccd_sensors17h(struct amdzentemp_softc *sc, int model) | | 369 | amdzentemp_probe_ccd_sensors17h(struct amdzentemp_softc *sc, int model) |
370 | { | | 370 | { |
371 | int maxreg; | | 371 | int maxreg; |
372 | | | 372 | |
373 | sc->sc_ccd_offset = 0x154; | | | |
374 | | | | |
375 | switch (model) { | | 373 | switch (model) { |
376 | case 0x00 ... 0x2f: /* Zen1, Zen+ */ | | 374 | case 0x00 ... 0x2f: /* Zen1, Zen+ */ |
| | | 375 | sc->sc_ccd_offset = 0x154; |
377 | maxreg = 4; | | 376 | maxreg = 4; |
378 | break; | | 377 | break; |
379 | case 0x30 ... 0x3f: /* Zen2 TR (Castle Peak)/EPYC (Rome) */ | | 378 | case 0x30 ... 0x3f: /* Zen2 TR (Castle Peak)/EPYC (Rome) */ |
380 | case 0x60 ... 0x7f: /* Zen2 Ryzen (Renoir APU, Matisse) */ | | 379 | case 0x60 ... 0x7f: /* Zen2 Ryzen (Renoir APU, Matisse) */ |
381 | case 0x90 ... 0x9f: /* Zen2 Ryzen (Van Gogh APU) */ | | 380 | case 0x90 ... 0x9f: /* Zen2 Ryzen (Van Gogh APU) */ |
| | | 381 | sc->sc_ccd_offset = 0x154; |
| | | 382 | maxreg = 8; |
| | | 383 | break; |
| | | 384 | case 0xa0 ... 0xaf: /* Zen2 Ryzen (Mendocino APU) */ |
| | | 385 | sc->sc_ccd_offset = 0x300; |
382 | maxreg = 8; | | 386 | maxreg = 8; |
383 | break; | | 387 | break; |
384 | default: | | 388 | default: |
385 | aprint_error_dev(sc->sc_dev, | | 389 | aprint_error_dev(sc->sc_dev, |
386 | "Unrecognized Family 17h Model: %02xh\n", model); | | 390 | "Unrecognized Family 17h Model: %02xh\n", model); |
387 | return 0; | | 391 | return 0; |
388 | } | | 392 | } |
389 | | | 393 | |
390 | return maxreg; | | 394 | return maxreg; |
391 | } | | 395 | } |
392 | | | 396 | |
393 | static int | | 397 | static int |
394 | amdzentemp_probe_ccd_sensors19h(struct amdzentemp_softc *sc, int model) | | 398 | amdzentemp_probe_ccd_sensors19h(struct amdzentemp_softc *sc, int model) |
395 | { | | 399 | { |
396 | int maxreg; | | 400 | int maxreg; |
397 | | | 401 | |
398 | switch (model) { | | 402 | switch (model) { |
399 | case 0x00 ... 0x0f: /* Zen3 EPYC "Milan" */ | | 403 | case 0x00 ... 0x0f: /* Zen3 EPYC "Milan" */ |
400 | case 0x20 ... 0x2f: /* Zen3 Ryzen "Vermeer" */ | | 404 | case 0x20 ... 0x2f: /* Zen3 Ryzen "Vermeer" */ |
401 | case 0x50 ... 0x5f: /* Zen3 Ryzen "Cezanne" */ | | 405 | case 0x50 ... 0x5f: /* Zen3 Ryzen "Cezanne" */ |
402 | sc->sc_ccd_offset = 0x154; | | 406 | sc->sc_ccd_offset = 0x154; |
403 | maxreg = 8; | | 407 | maxreg = 8; |
404 | break; | | 408 | break; |
405 | case 0x60 ... 0x6f: /* Zen4 Ryzen "Raphael" */ | | 409 | case 0x60 ... 0x6f: /* Zen4 Ryzen "Raphael" */ |
406 | case 0x70 ... 0x7f: /* Zen4 Ryzen "Phoenix" */ | | 410 | case 0x70 ... 0x7f: /* Zen4 Ryzen "Phoenix" */ |
407 | sc->sc_ccd_offset = 0x308; | | 411 | sc->sc_ccd_offset = 0x308; |
408 | maxreg = 8; | | 412 | maxreg = 8; |
409 | break; | | 413 | break; |
410 | case 0x40 ... 0x4f: /* Zen3+ "Rembrandt" */ | | 414 | case 0x40 ... 0x4f: /* Zen3+ "Rembrandt" */ |
411 | sc->sc_ccd_offset = 0x300; | | 415 | sc->sc_ccd_offset = 0x300; |
412 | maxreg = 8; | | 416 | maxreg = 8; |
413 | break; | | 417 | break; |
414 | case 0x10 ... 0x1f: /* Zen4 "Genoa" */ | | 418 | case 0x10 ... 0x1f: /* Zen4 "Genoa" */ |
415 | sc->sc_ccd_offset = 0x300; | | 419 | sc->sc_ccd_offset = 0x300; |
416 | maxreg = 12; | | 420 | maxreg = 12; |
417 | break; | | 421 | break; |
418 | default: | | 422 | default: |
419 | aprint_error_dev(sc->sc_dev, | | 423 | aprint_error_dev(sc->sc_dev, |
420 | "Unrecognized Family 19h Model: %02xh\n", model); | | 424 | "Unrecognized Family 19h Model: %02xh\n", model); |
421 | return 0; | | 425 | return 0; |
422 | } | | 426 | } |
423 | | | 427 | |
424 | return maxreg; | | 428 | return maxreg; |
425 | } | | 429 | } |
426 | | | 430 | |
427 | static int | | 431 | static int |
428 | amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *sc, int family, int model) | | 432 | amdzentemp_probe_ccd_sensors(struct amdzentemp_softc *sc, int family, int model) |
429 | { | | 433 | { |
430 | int nccd; | | 434 | int nccd; |
431 | | | 435 | |
432 | switch (family) { | | 436 | switch (family) { |
433 | case 0x17: | | 437 | case 0x17: |
434 | nccd = amdzentemp_probe_ccd_sensors17h(sc, model); | | 438 | nccd = amdzentemp_probe_ccd_sensors17h(sc, model); |
435 | break; | | 439 | break; |
436 | case 0x19: | | 440 | case 0x19: |
437 | nccd = amdzentemp_probe_ccd_sensors19h(sc, model); | | 441 | nccd = amdzentemp_probe_ccd_sensors19h(sc, model); |
438 | break; | | 442 | break; |
439 | default: | | 443 | default: |
440 | return 0; | | 444 | return 0; |
441 | } | | 445 | } |
442 | | | 446 | |
443 | return nccd; | | 447 | return nccd; |
444 | } | | 448 | } |
445 | | | 449 | |
446 | static void | | 450 | static void |
447 | amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *sc) | | 451 | amdzentemp_setup_ccd_sensors(struct amdzentemp_softc *sc) |
448 | { | | 452 | { |
449 | envsys_data_t *edata; | | 453 | envsys_data_t *edata; |
450 | size_t i; | | 454 | size_t i; |
451 | uint32_t temp; | | 455 | uint32_t temp; |
452 | int error; | | 456 | int error; |
453 | | | 457 | |
454 | for (i = 0; i < sc->sc_numsensors - 1; i++) { | | 458 | for (i = 0; i < sc->sc_numsensors - 1; i++) { |
455 | error = amdsmn_read(sc->sc_smn, | | 459 | error = amdsmn_read(sc->sc_smn, |
456 | AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)), | | 460 | AMD_17H_CUR_TMP + sc->sc_ccd_offset + (i * sizeof(temp)), |
457 | &temp); | | 461 | &temp); |
458 | if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) | | 462 | if (error || !ISSET(temp, AMD_17H_CCD_TMP_VALID)) |
459 | continue; | | 463 | continue; |
460 | | | 464 | |
461 | edata = &sc->sc_sensor[1 + i]; | | 465 | edata = &sc->sc_sensor[1 + i]; |
462 | edata->units = ENVSYS_STEMP; | | 466 | edata->units = ENVSYS_STEMP; |
463 | edata->state = ENVSYS_SVALID; | | 467 | edata->state = ENVSYS_SVALID; |
464 | edata->flags = ENVSYS_FHAS_ENTROPY; | | 468 | edata->flags = ENVSYS_FHAS_ENTROPY; |
465 | edata->private = CCD_BASE + i; | | 469 | edata->private = CCD_BASE + i; |
466 | snprintf(edata->desc, sizeof(edata->desc), | | 470 | snprintf(edata->desc, sizeof(edata->desc), |
467 | "cpu%u ccd%zu temperature", device_unit(sc->sc_dev), i); | | 471 | "cpu%u ccd%zu temperature", device_unit(sc->sc_dev), i); |
468 | } | | 472 | } |
469 | } | | 473 | } |
470 | | | 474 | |
471 | MODULE(MODULE_CLASS_DRIVER, amdzentemp, "sysmon_envsys,amdsmn"); | | 475 | MODULE(MODULE_CLASS_DRIVER, amdzentemp, "sysmon_envsys,amdsmn"); |
472 | | | 476 | |
473 | #ifdef _MODULE | | 477 | #ifdef _MODULE |
474 | #include "ioconf.c" | | 478 | #include "ioconf.c" |
475 | #endif | | 479 | #endif |
476 | | | 480 | |
477 | static int | | 481 | static int |
478 | amdzentemp_modcmd(modcmd_t cmd, void *aux) | | 482 | amdzentemp_modcmd(modcmd_t cmd, void *aux) |
479 | { | | 483 | { |
480 | int error = 0; | | 484 | int error = 0; |
481 | | | 485 | |
482 | switch (cmd) { | | 486 | switch (cmd) { |
483 | case MODULE_CMD_INIT: | | 487 | case MODULE_CMD_INIT: |
484 | #ifdef _MODULE | | 488 | #ifdef _MODULE |
485 | error = config_init_component(cfdriver_ioconf_amdzentemp, | | 489 | error = config_init_component(cfdriver_ioconf_amdzentemp, |
486 | cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); | | 490 | cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); |
487 | #endif | | 491 | #endif |
488 | return error; | | 492 | return error; |
489 | case MODULE_CMD_FINI: | | 493 | case MODULE_CMD_FINI: |
490 | #ifdef _MODULE | | 494 | #ifdef _MODULE |
491 | error = config_fini_component(cfdriver_ioconf_amdzentemp, | | 495 | error = config_fini_component(cfdriver_ioconf_amdzentemp, |
492 | cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); | | 496 | cfattach_ioconf_amdzentemp, cfdata_ioconf_amdzentemp); |
493 | #endif | | 497 | #endif |
494 | return error; | | 498 | return error; |
495 | default: | | 499 | default: |
496 | return ENOTTY; | | 500 | return ENOTTY; |
497 | } | | 501 | } |
498 | } | | 502 | } |