| @@ -1,554 +1,557 @@ | | | @@ -1,554 +1,557 @@ |
1 | /* $NetBSD: amdtemp.c,v 1.12 2011/07/31 22:04:07 jmcneill Exp $ */ | | 1 | /* $NetBSD: amdtemp.c,v 1.12.8.1 2012/03/08 17:38:03 riz 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 The NetBSD Foundation, Inc. | | 5 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * This code is derived from software contributed to The NetBSD Foundation | | 8 | * This code is derived from software contributed to The NetBSD Foundation |
9 | * by Christoph Egger. | | 9 | * by Christoph Egger. |
10 | * | | 10 | * |
11 | * Redistribution and use in source and binary forms, with or without | | 11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions | | 12 | * modification, are permitted provided that the following conditions |
13 | * are met: | | 13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright | | 14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. | | 15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright | | 16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the | | 17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. | | 18 | * documentation and/or other materials provided with the distribution. |
19 | * | | 19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. | | 30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | /* | | 33 | /* |
34 | * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> | | 34 | * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru> |
35 | * | | 35 | * |
36 | * Permission to use, copy, modify, and distribute this software for any | | 36 | * Permission to use, copy, modify, and distribute this software for any |
37 | * purpose with or without fee is hereby granted, provided that the above | | 37 | * purpose with or without fee is hereby granted, provided that the above |
38 | * copyright notice and this permission notice appear in all copies. | | 38 | * copyright notice and this permission notice appear in all copies. |
39 | * | | 39 | * |
40 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 40 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
41 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 41 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
42 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 42 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
43 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 43 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
44 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | | 44 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
45 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | | 45 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
46 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | | 46 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
47 | */ | | 47 | */ |
48 | | | 48 | |
49 | | | 49 | |
50 | #include <sys/cdefs.h> | | 50 | #include <sys/cdefs.h> |
51 | __KERNEL_RCSID(0, "$NetBSD: amdtemp.c,v 1.12 2011/07/31 22:04:07 jmcneill Exp $ "); | | 51 | __KERNEL_RCSID(0, "$NetBSD: amdtemp.c,v 1.12.8.1 2012/03/08 17:38:03 riz Exp $ "); |
52 | | | 52 | |
53 | #include <sys/param.h> | | 53 | #include <sys/param.h> |
54 | #include <sys/bus.h> | | 54 | #include <sys/bus.h> |
55 | #include <sys/cpu.h> | | 55 | #include <sys/cpu.h> |
56 | #include <sys/systm.h> | | 56 | #include <sys/systm.h> |
57 | #include <sys/device.h> | | 57 | #include <sys/device.h> |
58 | #include <sys/kmem.h> | | 58 | #include <sys/kmem.h> |
59 | #include <sys/module.h> | | 59 | #include <sys/module.h> |
60 | | | 60 | |
61 | #include <machine/specialreg.h> | | 61 | #include <machine/specialreg.h> |
62 | | | 62 | |
63 | #include <dev/pci/pcireg.h> | | 63 | #include <dev/pci/pcireg.h> |
64 | #include <dev/pci/pcivar.h> | | 64 | #include <dev/pci/pcivar.h> |
65 | #include <dev/pci/pcidevs.h> | | 65 | #include <dev/pci/pcidevs.h> |
66 | | | 66 | |
67 | #include <dev/sysmon/sysmonvar.h> | | 67 | #include <dev/sysmon/sysmonvar.h> |
68 | | | 68 | |
69 | /* | | 69 | /* |
70 | * AMD K8: | | 70 | * AMD K8: |
71 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf | | 71 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf |
72 | * AMD K8 Errata: #141 | | 72 | * AMD K8 Errata: #141 |
73 | * http://support.amd.com/us/Processor_TechDocs/33610_PUB_Rev3%2042v3.pdf | | 73 | * http://support.amd.com/us/Processor_TechDocs/33610_PUB_Rev3%2042v3.pdf |
74 | * | | 74 | * |
75 | * Family10h: | | 75 | * Family10h: |
76 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/31116.PDF | | 76 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/31116.PDF |
77 | * Family10h Errata: #319 | | 77 | * Family10h Errata: #319 |
78 | * http://support.amd.com/de/Processor_TechDocs/41322.pdf | | 78 | * http://support.amd.com/de/Processor_TechDocs/41322.pdf |
79 | * | | 79 | * |
80 | * Family11h: | | 80 | * Family11h: |
81 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/41256.pdf | | 81 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/41256.pdf |
82 | */ | | 82 | */ |
83 | | | 83 | |
84 | /* AMD Processors, Function 3 -- Miscellaneous Control | | 84 | /* AMD Processors, Function 3 -- Miscellaneous Control |
85 | */ | | 85 | */ |
86 | | | 86 | |
87 | /* Function 3 Registers */ | | 87 | /* Function 3 Registers */ |
88 | #define THERMTRIP_STAT_R 0xe4 | | 88 | #define THERMTRIP_STAT_R 0xe4 |
89 | #define NORTHBRIDGE_CAP_R 0xe8 | | 89 | #define NORTHBRIDGE_CAP_R 0xe8 |
90 | #define CPUID_FAMILY_MODEL_R 0xfc | | 90 | #define CPUID_FAMILY_MODEL_R 0xfc |
91 | | | 91 | |
92 | /* | | 92 | /* |
93 | * AMD NPT Family 0Fh Processors, Function 3 -- Miscellaneous Control | | 93 | * AMD NPT Family 0Fh Processors, Function 3 -- Miscellaneous Control |
94 | */ | | 94 | */ |
95 | | | 95 | |
96 | /* Bits within Thermtrip Status Register */ | | 96 | /* Bits within Thermtrip Status Register */ |
97 | #define K8_THERM_SENSE_SEL (1 << 6) | | 97 | #define K8_THERM_SENSE_SEL (1 << 6) |
98 | #define K8_THERM_SENSE_CORE_SEL (1 << 2) | | 98 | #define K8_THERM_SENSE_CORE_SEL (1 << 2) |
99 | | | 99 | |
100 | /* Flip core and sensor selection bits */ | | 100 | /* Flip core and sensor selection bits */ |
101 | #define K8_T_SEL_C0(v) (v |= K8_THERM_SENSE_CORE_SEL) | | 101 | #define K8_T_SEL_C0(v) (v |= K8_THERM_SENSE_CORE_SEL) |
102 | #define K8_T_SEL_C1(v) (v &= ~(K8_THERM_SENSE_CORE_SEL)) | | 102 | #define K8_T_SEL_C1(v) (v &= ~(K8_THERM_SENSE_CORE_SEL)) |
103 | #define K8_T_SEL_S0(v) (v &= ~(K8_THERM_SENSE_SEL)) | | 103 | #define K8_T_SEL_S0(v) (v &= ~(K8_THERM_SENSE_SEL)) |
104 | #define K8_T_SEL_S1(v) (v |= K8_THERM_SENSE_SEL) | | 104 | #define K8_T_SEL_S1(v) (v |= K8_THERM_SENSE_SEL) |
105 | | | 105 | |
106 | | | 106 | |
107 | | | 107 | |
108 | /* | | 108 | /* |
109 | * AMD Family 10h Processors, Function 3 -- Miscellaneous Control | | 109 | * AMD Family 10h Processors, Function 3 -- Miscellaneous Control |
110 | */ | | 110 | */ |
111 | | | 111 | |
112 | /* Function 3 Registers */ | | 112 | /* Function 3 Registers */ |
113 | #define F10_TEMPERATURE_CTL_R 0xa4 | | 113 | #define F10_TEMPERATURE_CTL_R 0xa4 |
114 | | | 114 | |
115 | /* Bits within Reported Temperature Control Register */ | | 115 | /* Bits within Reported Temperature Control Register */ |
116 | #define F10_TEMP_CURTEMP (1 << 21) | | 116 | #define F10_TEMP_CURTEMP (1 << 21) |
117 | | | 117 | |
118 | /* | | 118 | /* |
119 | * Revision Guide for AMD NPT Family 0Fh Processors, | | 119 | * Revision Guide for AMD NPT Family 0Fh Processors, |
120 | * Publication # 33610, Revision 3.30, February 2008 | | 120 | * Publication # 33610, Revision 3.30, February 2008 |
121 | */ | | 121 | */ |
122 | #define K8_SOCKET_F 1 /* Server */ | | 122 | #define K8_SOCKET_F 1 /* Server */ |
123 | #define K8_SOCKET_AM2 2 /* Desktop */ | | 123 | #define K8_SOCKET_AM2 2 /* Desktop */ |
124 | #define K8_SOCKET_S1 3 /* Laptop */ | | 124 | #define K8_SOCKET_S1 3 /* Laptop */ |
125 | | | 125 | |
126 | static const struct { | | 126 | static const struct { |
127 | const char rev[5]; | | 127 | const char rev[5]; |
128 | const struct { | | 128 | const struct { |
129 | const pcireg_t cpuid; | | 129 | const pcireg_t cpuid; |
130 | const uint8_t socket; | | 130 | const uint8_t socket; |
131 | } cpu[5]; | | 131 | } cpu[5]; |
132 | } amdtemp_core[] = { | | 132 | } amdtemp_core[] = { |
133 | { "BH-F", { { 0x00040FB0, K8_SOCKET_AM2 }, /* F2 */ | | 133 | { "BH-F", { { 0x00040FB0, K8_SOCKET_AM2 }, /* F2 */ |
134 | { 0x00040F80, K8_SOCKET_S1 }, /* F2 */ | | 134 | { 0x00040F80, K8_SOCKET_S1 }, /* F2 */ |
135 | { 0, 0 }, { 0, 0 }, { 0, 0 } } }, | | 135 | { 0, 0 }, { 0, 0 }, { 0, 0 } } }, |
136 | { "DH-F", { { 0x00040FF0, K8_SOCKET_AM2 }, /* F2 */ | | 136 | { "DH-F", { { 0x00040FF0, K8_SOCKET_AM2 }, /* F2 */ |
137 | { 0x00040FC0, K8_SOCKET_S1 }, /* F2 */ | | 137 | { 0x00040FC0, K8_SOCKET_S1 }, /* F2 */ |
138 | { 0x00050FF0, K8_SOCKET_AM2 }, /* F2, F3 */ | | 138 | { 0x00050FF0, K8_SOCKET_AM2 }, /* F2, F3 */ |
139 | { 0, 0 }, { 0, 0 } } }, | | 139 | { 0, 0 }, { 0, 0 } } }, |
140 | { "JH-F", { { 0x00040F10, K8_SOCKET_F }, /* F2, F3 */ | | 140 | { "JH-F", { { 0x00040F10, K8_SOCKET_F }, /* F2, F3 */ |
141 | { 0x00040F30, K8_SOCKET_AM2 }, /* F2, F3 */ | | 141 | { 0x00040F30, K8_SOCKET_AM2 }, /* F2, F3 */ |
142 | { 0x000C0F10, K8_SOCKET_F }, /* F3 */ | | 142 | { 0x000C0F10, K8_SOCKET_F }, /* F3 */ |
143 | { 0, 0 }, { 0, 0 } } }, | | 143 | { 0, 0 }, { 0, 0 } } }, |
144 | { "BH-G", { { 0x00060FB0, K8_SOCKET_AM2 }, /* G1, G2 */ | | 144 | { "BH-G", { { 0x00060FB0, K8_SOCKET_AM2 }, /* G1, G2 */ |
145 | { 0x00060F80, K8_SOCKET_S1 }, /* G1, G2 */ | | 145 | { 0x00060F80, K8_SOCKET_S1 }, /* G1, G2 */ |
146 | { 0, 0 }, { 0, 0 }, { 0, 0 } } }, | | 146 | { 0, 0 }, { 0, 0 }, { 0, 0 } } }, |
147 | { "DH-G", { { 0x00060FF0, K8_SOCKET_AM2 }, /* G1, G2 */ | | 147 | { "DH-G", { { 0x00060FF0, K8_SOCKET_AM2 }, /* G1, G2 */ |
148 | { 0x00060FC0, K8_SOCKET_S1 }, /* G2 */ | | 148 | { 0x00060FC0, K8_SOCKET_S1 }, /* G2 */ |
149 | { 0x00070FF0, K8_SOCKET_AM2 }, /* G1, G2 */ | | 149 | { 0x00070FF0, K8_SOCKET_AM2 }, /* G1, G2 */ |
150 | { 0x00070FC0, K8_SOCKET_S1 }, /* G2 */ | | 150 | { 0x00070FC0, K8_SOCKET_S1 }, /* G2 */ |
151 | { 0, 0 } } } | | 151 | { 0, 0 } } } |
152 | }; | | 152 | }; |
153 | | | 153 | |
154 | | | 154 | |
155 | struct amdtemp_softc { | | 155 | struct amdtemp_softc { |
156 | pci_chipset_tag_t sc_pc; | | 156 | pci_chipset_tag_t sc_pc; |
157 | pcitag_t sc_pcitag; | | 157 | pcitag_t sc_pcitag; |
158 | | | 158 | |
159 | struct sysmon_envsys *sc_sme; | | 159 | struct sysmon_envsys *sc_sme; |
160 | envsys_data_t *sc_sensor; | | 160 | envsys_data_t *sc_sensor; |
161 | size_t sc_sensor_len; | | 161 | size_t sc_sensor_len; |
162 | | | 162 | |
163 | char sc_rev; | | 163 | char sc_rev; |
164 | int8_t sc_numsensors; | | 164 | int8_t sc_numsensors; |
165 | uint32_t sc_family; | | 165 | uint32_t sc_family; |
166 | int32_t sc_adjustment; | | 166 | int32_t sc_adjustment; |
167 | }; | | 167 | }; |
168 | | | 168 | |
169 | | | 169 | |
170 | static int amdtemp_match(device_t, cfdata_t, void *); | | 170 | static int amdtemp_match(device_t, cfdata_t, void *); |
171 | static void amdtemp_attach(device_t, device_t, void *); | | 171 | static void amdtemp_attach(device_t, device_t, void *); |
172 | static int amdtemp_detach(device_t, int); | | 172 | static int amdtemp_detach(device_t, int); |
173 | | | 173 | |
174 | static void amdtemp_k8_init(struct amdtemp_softc *, pcireg_t); | | 174 | static void amdtemp_k8_init(struct amdtemp_softc *, pcireg_t); |
175 | static void amdtemp_k8_setup_sensors(struct amdtemp_softc *, int); | | 175 | static void amdtemp_k8_setup_sensors(struct amdtemp_softc *, int); |
176 | static void amdtemp_k8_refresh(struct sysmon_envsys *, envsys_data_t *); | | 176 | static void amdtemp_k8_refresh(struct sysmon_envsys *, envsys_data_t *); |
177 | | | 177 | |
178 | static void amdtemp_family10_init(struct amdtemp_softc *); | | 178 | static void amdtemp_family10_init(struct amdtemp_softc *); |
179 | static void amdtemp_family10_setup_sensors(struct amdtemp_softc *, int); | | 179 | static void amdtemp_family10_setup_sensors(struct amdtemp_softc *, int); |
180 | static void amdtemp_family10_refresh(struct sysmon_envsys *, envsys_data_t *); | | 180 | static void amdtemp_family10_refresh(struct sysmon_envsys *, envsys_data_t *); |
181 | | | 181 | |
182 | CFATTACH_DECL_NEW(amdtemp, sizeof(struct amdtemp_softc), | | 182 | CFATTACH_DECL_NEW(amdtemp, sizeof(struct amdtemp_softc), |
183 | amdtemp_match, amdtemp_attach, amdtemp_detach, NULL); | | 183 | amdtemp_match, amdtemp_attach, amdtemp_detach, NULL); |
184 | | | 184 | |
185 | static int | | 185 | static int |
186 | amdtemp_match(device_t parent, cfdata_t match, void *aux) | | 186 | amdtemp_match(device_t parent, cfdata_t match, void *aux) |
187 | { | | 187 | { |
188 | struct pci_attach_args *pa = aux; | | 188 | struct pci_attach_args *pa = aux; |
189 | pcireg_t cpu_signature; | | 189 | pcireg_t cpu_signature; |
190 | uint32_t family; | | 190 | uint32_t family; |
191 | | | 191 | |
192 | if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD) | | 192 | if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD) |
193 | return 0; | | 193 | return 0; |
194 | | | 194 | |
195 | switch (PCI_PRODUCT(pa->pa_id)) { | | 195 | switch (PCI_PRODUCT(pa->pa_id)) { |
196 | case PCI_PRODUCT_AMD_AMD64_MISC: | | 196 | case PCI_PRODUCT_AMD_AMD64_MISC: |
197 | case PCI_PRODUCT_AMD_AMD64_F10_MISC: | | 197 | case PCI_PRODUCT_AMD_AMD64_F10_MISC: |
198 | case PCI_PRODUCT_AMD_AMD64_F11_MISC: | | 198 | case PCI_PRODUCT_AMD_AMD64_F11_MISC: |
199 | case PCI_PRODUCT_AMD_F14_NB: | | 199 | case PCI_PRODUCT_AMD_F14_NB: /* Family12h too */ |
200 | break; | | 200 | break; |
201 | default: | | 201 | default: |
202 | return 0; | | 202 | return 0; |
203 | } | | 203 | } |
204 | | | 204 | |
205 | cpu_signature = pci_conf_read(pa->pa_pc, | | 205 | cpu_signature = pci_conf_read(pa->pa_pc, |
206 | pa->pa_tag, CPUID_FAMILY_MODEL_R); | | 206 | pa->pa_tag, CPUID_FAMILY_MODEL_R); |
207 | | | 207 | |
208 | /* This CPUID northbridge register has been introduced | | 208 | /* This CPUID northbridge register has been introduced |
209 | * in Revision F */ | | 209 | * in Revision F */ |
210 | if (cpu_signature == 0x0) | | 210 | if (cpu_signature == 0x0) |
211 | return 0; | | 211 | return 0; |
212 | | | 212 | |
213 | family = CPUID2FAMILY(cpu_signature); | | 213 | family = CPUID2FAMILY(cpu_signature); |
214 | if (family == 0xf) | | 214 | if (family == 0xf) |
215 | family += CPUID2EXTFAMILY(cpu_signature); | | 215 | family += CPUID2EXTFAMILY(cpu_signature); |
216 | | | 216 | |
217 | /* Errata #319: This has been fixed in Revision C2. */ | | 217 | /* Errata #319: This has been fixed in Revision C2. */ |
218 | if (family == 0x10) { | | 218 | if (family == 0x10) { |
219 | if (CPUID2MODEL(cpu_signature) < 4) | | 219 | if (CPUID2MODEL(cpu_signature) < 4) |
220 | return 0; | | 220 | return 0; |
221 | if (CPUID2MODEL(cpu_signature) == 4 | | 221 | if (CPUID2MODEL(cpu_signature) == 4 |
222 | && CPUID2STEPPING(cpu_signature) < 2) | | 222 | && CPUID2STEPPING(cpu_signature) < 2) |
223 | return 0; | | 223 | return 0; |
224 | } | | 224 | } |
225 | | | 225 | |
226 | | | 226 | |
227 | /* Not yet supported CPUs */ | | 227 | /* Not yet supported CPUs */ |
228 | if (family > 0x14) | | 228 | if (family > 0x14) |
229 | return 0; | | 229 | return 0; |
230 | | | 230 | |
231 | return 2; /* supercede pchb(4) */ | | 231 | return 2; /* supercede pchb(4) */ |
232 | } | | 232 | } |
233 | | | 233 | |
234 | static void | | 234 | static void |
235 | amdtemp_attach(device_t parent, device_t self, void *aux) | | 235 | amdtemp_attach(device_t parent, device_t self, void *aux) |
236 | { | | 236 | { |
237 | struct amdtemp_softc *sc = device_private(self); | | 237 | struct amdtemp_softc *sc = device_private(self); |
238 | struct pci_attach_args *pa = aux; | | 238 | struct pci_attach_args *pa = aux; |
239 | pcireg_t cpu_signature; | | 239 | pcireg_t cpu_signature; |
240 | int error; | | 240 | int error; |
241 | uint8_t i; | | 241 | uint8_t i; |
242 | | | 242 | |
243 | aprint_naive("\n"); | | 243 | aprint_naive("\n"); |
244 | aprint_normal(": AMD CPU Temperature Sensors"); | | 244 | aprint_normal(": AMD CPU Temperature Sensors"); |
245 | | | 245 | |
246 | cpu_signature = pci_conf_read(pa->pa_pc, | | 246 | cpu_signature = pci_conf_read(pa->pa_pc, |
247 | pa->pa_tag, CPUID_FAMILY_MODEL_R); | | 247 | pa->pa_tag, CPUID_FAMILY_MODEL_R); |
248 | | | 248 | |
249 | /* If we hit this, then match routine is wrong. */ | | 249 | /* If we hit this, then match routine is wrong. */ |
250 | KASSERT(cpu_signature != 0x0); | | 250 | KASSERT(cpu_signature != 0x0); |
251 | | | 251 | |
252 | sc->sc_family = CPUID2FAMILY(cpu_signature); | | 252 | sc->sc_family = CPUID2FAMILY(cpu_signature); |
253 | sc->sc_family += CPUID2EXTFAMILY(cpu_signature); | | 253 | sc->sc_family += CPUID2EXTFAMILY(cpu_signature); |
254 | | | 254 | |
255 | KASSERT(sc->sc_family >= 0xf); | | 255 | KASSERT(sc->sc_family >= 0xf); |
256 | | | 256 | |
257 | sc->sc_sme = NULL; | | 257 | sc->sc_sme = NULL; |
258 | sc->sc_sensor = NULL; | | 258 | sc->sc_sensor = NULL; |
259 | | | 259 | |
260 | sc->sc_pc = pa->pa_pc; | | 260 | sc->sc_pc = pa->pa_pc; |
261 | sc->sc_pcitag = pa->pa_tag; | | 261 | sc->sc_pcitag = pa->pa_tag; |
262 | sc->sc_adjustment = 0; | | 262 | sc->sc_adjustment = 0; |
263 | | | 263 | |
264 | switch (sc->sc_family) { | | 264 | switch (sc->sc_family) { |
265 | case 0xf: /* AMD K8 NPT */ | | 265 | case 0xf: /* AMD K8 NPT */ |
266 | amdtemp_k8_init(sc, cpu_signature); | | 266 | amdtemp_k8_init(sc, cpu_signature); |
267 | break; | | 267 | break; |
268 | | | 268 | |
269 | case 0x10: /* AMD Barcelona/Phenom */ | | 269 | case 0x10: /* AMD Barcelona/Phenom */ |
270 | case 0x11: /* AMD Griffin */ | | 270 | case 0x11: /* AMD Griffin */ |
271 | case 0x14: /* AMD Fusion */ | | 271 | case 0x12: /* AMD Lynx/Sabine (Llano) */ |
| | | 272 | case 0x14: /* AMD Brazos (Ontario/Zacate/Desna) */ |
272 | amdtemp_family10_init(sc); | | 273 | amdtemp_family10_init(sc); |
273 | break; | | 274 | break; |
274 | | | 275 | |
275 | default: | | 276 | default: |
276 | aprint_normal(", family 0x%x not supported\n", | | 277 | aprint_normal(", family 0x%x not supported\n", |
277 | sc->sc_family); | | 278 | sc->sc_family); |
278 | return; | | 279 | return; |
279 | } | | 280 | } |
280 | | | 281 | |
281 | aprint_normal("\n"); | | 282 | aprint_normal("\n"); |
282 | | | 283 | |
283 | if (sc->sc_adjustment != 0) | | 284 | if (sc->sc_adjustment != 0) |
284 | aprint_debug_dev(self, "Workaround enabled\n"); | | 285 | aprint_debug_dev(self, "Workaround enabled\n"); |
285 | | | 286 | |
286 | sc->sc_sme = sysmon_envsys_create(); | | 287 | sc->sc_sme = sysmon_envsys_create(); |
287 | sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors; | | 288 | sc->sc_sensor_len = sizeof(envsys_data_t) * sc->sc_numsensors; |
288 | sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP); | | 289 | sc->sc_sensor = kmem_zalloc(sc->sc_sensor_len, KM_SLEEP); |
289 | | | 290 | |
290 | if (sc->sc_sensor == NULL) | | 291 | if (sc->sc_sensor == NULL) |
291 | goto bad; | | 292 | goto bad; |
292 | | | 293 | |
293 | switch (sc->sc_family) { | | 294 | switch (sc->sc_family) { |
294 | case 0xf: | | 295 | case 0xf: |
295 | amdtemp_k8_setup_sensors(sc, device_unit(self)); | | 296 | amdtemp_k8_setup_sensors(sc, device_unit(self)); |
296 | break; | | 297 | break; |
297 | case 0x10: | | 298 | case 0x10: |
298 | case 0x11: | | 299 | case 0x11: |
| | | 300 | case 0x12: |
299 | case 0x14: | | 301 | case 0x14: |
300 | amdtemp_family10_setup_sensors(sc, device_unit(self)); | | 302 | amdtemp_family10_setup_sensors(sc, device_unit(self)); |
301 | break; | | 303 | break; |
302 | } | | 304 | } |
303 | | | 305 | |
304 | /* | | 306 | /* |
305 | * Set properties in sensors. | | 307 | * Set properties in sensors. |
306 | */ | | 308 | */ |
307 | for (i = 0; i < sc->sc_numsensors; i++) { | | 309 | for (i = 0; i < sc->sc_numsensors; i++) { |
308 | if (sysmon_envsys_sensor_attach(sc->sc_sme, | | 310 | if (sysmon_envsys_sensor_attach(sc->sc_sme, |
309 | &sc->sc_sensor[i])) | | 311 | &sc->sc_sensor[i])) |
310 | goto bad; | | 312 | goto bad; |
311 | } | | 313 | } |
312 | | | 314 | |
313 | /* | | 315 | /* |
314 | * Register the sysmon_envsys device. | | 316 | * Register the sysmon_envsys device. |
315 | */ | | 317 | */ |
316 | sc->sc_sme->sme_name = device_xname(self); | | 318 | sc->sc_sme->sme_name = device_xname(self); |
317 | sc->sc_sme->sme_cookie = sc; | | 319 | sc->sc_sme->sme_cookie = sc; |
318 | | | 320 | |
319 | switch (sc->sc_family) { | | 321 | switch (sc->sc_family) { |
320 | case 0xf: | | 322 | case 0xf: |
321 | sc->sc_sme->sme_refresh = amdtemp_k8_refresh; | | 323 | sc->sc_sme->sme_refresh = amdtemp_k8_refresh; |
322 | break; | | 324 | break; |
323 | case 0x10: | | 325 | case 0x10: |
324 | case 0x11: | | 326 | case 0x11: |
| | | 327 | case 0x12: |
325 | case 0x14: | | 328 | case 0x14: |
326 | sc->sc_sme->sme_refresh = amdtemp_family10_refresh; | | 329 | sc->sc_sme->sme_refresh = amdtemp_family10_refresh; |
327 | break; | | 330 | break; |
328 | } | | 331 | } |
329 | | | 332 | |
330 | error = sysmon_envsys_register(sc->sc_sme); | | 333 | error = sysmon_envsys_register(sc->sc_sme); |
331 | if (error) { | | 334 | if (error) { |
332 | aprint_error_dev(self, "unable to register with sysmon " | | 335 | aprint_error_dev(self, "unable to register with sysmon " |
333 | "(error=%d)\n", error); | | 336 | "(error=%d)\n", error); |
334 | goto bad; | | 337 | goto bad; |
335 | } | | 338 | } |
336 | | | 339 | |
337 | (void)pmf_device_register(self, NULL, NULL); | | 340 | (void)pmf_device_register(self, NULL, NULL); |
338 | | | 341 | |
339 | return; | | 342 | return; |
340 | | | 343 | |
341 | bad: | | 344 | bad: |
342 | if (sc->sc_sme != NULL) { | | 345 | if (sc->sc_sme != NULL) { |
343 | sysmon_envsys_destroy(sc->sc_sme); | | 346 | sysmon_envsys_destroy(sc->sc_sme); |
344 | sc->sc_sme = NULL; | | 347 | sc->sc_sme = NULL; |
345 | } | | 348 | } |
346 | | | 349 | |
347 | if (sc->sc_sensor != NULL) { | | 350 | if (sc->sc_sensor != NULL) { |
348 | kmem_free(sc->sc_sensor, sc->sc_sensor_len); | | 351 | kmem_free(sc->sc_sensor, sc->sc_sensor_len); |
349 | sc->sc_sensor = NULL; | | 352 | sc->sc_sensor = NULL; |
350 | } | | 353 | } |
351 | } | | 354 | } |
352 | | | 355 | |
353 | static int | | 356 | static int |
354 | amdtemp_detach(device_t self, int flags) | | 357 | amdtemp_detach(device_t self, int flags) |
355 | { | | 358 | { |
356 | struct amdtemp_softc *sc = device_private(self); | | 359 | struct amdtemp_softc *sc = device_private(self); |
357 | | | 360 | |
358 | if (sc->sc_sme != NULL) | | 361 | if (sc->sc_sme != NULL) |
359 | sysmon_envsys_unregister(sc->sc_sme); | | 362 | sysmon_envsys_unregister(sc->sc_sme); |
360 | | | 363 | |
361 | if (sc->sc_sensor != NULL) | | 364 | if (sc->sc_sensor != NULL) |
362 | kmem_free(sc->sc_sensor, sc->sc_sensor_len); | | 365 | kmem_free(sc->sc_sensor, sc->sc_sensor_len); |
363 | | | 366 | |
364 | return 0; | | 367 | return 0; |
365 | } | | 368 | } |
366 | | | 369 | |
367 | static void | | 370 | static void |
368 | amdtemp_k8_init(struct amdtemp_softc *sc, pcireg_t cpu_signature) | | 371 | amdtemp_k8_init(struct amdtemp_softc *sc, pcireg_t cpu_signature) |
369 | { | | 372 | { |
370 | pcireg_t data; | | 373 | pcireg_t data; |
371 | uint32_t cmpcap; | | 374 | uint32_t cmpcap; |
372 | uint8_t i, j; | | 375 | uint8_t i, j; |
373 | | | 376 | |
374 | aprint_normal(" (K8"); | | 377 | aprint_normal(" (K8"); |
375 | | | 378 | |
376 | for (i = 0; i < __arraycount(amdtemp_core) && sc->sc_rev == '\0'; i++) { | | 379 | for (i = 0; i < __arraycount(amdtemp_core) && sc->sc_rev == '\0'; i++) { |
377 | for (j = 0; amdtemp_core[i].cpu[j].cpuid != 0; j++) { | | 380 | for (j = 0; amdtemp_core[i].cpu[j].cpuid != 0; j++) { |
378 | if ((cpu_signature & ~0xf) | | 381 | if ((cpu_signature & ~0xf) |
379 | != amdtemp_core[i].cpu[j].cpuid) | | 382 | != amdtemp_core[i].cpu[j].cpuid) |
380 | continue; | | 383 | continue; |
381 | | | 384 | |
382 | sc->sc_rev = amdtemp_core[i].rev[3]; | | 385 | sc->sc_rev = amdtemp_core[i].rev[3]; |
383 | aprint_normal(": core rev %.4s%.1x", | | 386 | aprint_normal(": core rev %.4s%.1x", |
384 | amdtemp_core[i].rev, | | 387 | amdtemp_core[i].rev, |
385 | CPUID2STEPPING(cpu_signature)); | | 388 | CPUID2STEPPING(cpu_signature)); |
386 | | | 389 | |
387 | switch (amdtemp_core[i].cpu[j].socket) { | | 390 | switch (amdtemp_core[i].cpu[j].socket) { |
388 | case K8_SOCKET_AM2: | | 391 | case K8_SOCKET_AM2: |
389 | if (sc->sc_rev == 'G') | | 392 | if (sc->sc_rev == 'G') |
390 | sc->sc_adjustment = 21000000; | | 393 | sc->sc_adjustment = 21000000; |
391 | aprint_normal(", socket AM2"); | | 394 | aprint_normal(", socket AM2"); |
392 | break; | | 395 | break; |
393 | case K8_SOCKET_S1: | | 396 | case K8_SOCKET_S1: |
394 | aprint_normal(", socket S1"); | | 397 | aprint_normal(", socket S1"); |
395 | break; | | 398 | break; |
396 | case K8_SOCKET_F: | | 399 | case K8_SOCKET_F: |
397 | aprint_normal(", socket F"); | | 400 | aprint_normal(", socket F"); |
398 | break; | | 401 | break; |
399 | } | | 402 | } |
400 | } | | 403 | } |
401 | } | | 404 | } |
402 | | | 405 | |
403 | if (sc->sc_rev == '\0') { | | 406 | if (sc->sc_rev == '\0') { |
404 | /* CPUID Family Model Register was introduced in | | 407 | /* CPUID Family Model Register was introduced in |
405 | * Revision F */ | | 408 | * Revision F */ |
406 | sc->sc_rev = 'G'; /* newer than E, assume G */ | | 409 | sc->sc_rev = 'G'; /* newer than E, assume G */ |
407 | aprint_normal(": cpuid 0x%x", cpu_signature); | | 410 | aprint_normal(": cpuid 0x%x", cpu_signature); |
408 | } | | 411 | } |
409 | | | 412 | |
410 | aprint_normal(")"); | | 413 | aprint_normal(")"); |
411 | | | 414 | |
412 | data = pci_conf_read(sc->sc_pc, sc->sc_pcitag, NORTHBRIDGE_CAP_R); | | 415 | data = pci_conf_read(sc->sc_pc, sc->sc_pcitag, NORTHBRIDGE_CAP_R); |
413 | cmpcap = (data >> 12) & 0x3; | | 416 | cmpcap = (data >> 12) & 0x3; |
414 | | | 417 | |
415 | sc->sc_numsensors = cmpcap ? 4 : 2; | | 418 | sc->sc_numsensors = cmpcap ? 4 : 2; |
416 | } | | 419 | } |
417 | | | 420 | |
418 | | | 421 | |
419 | static void | | 422 | static void |
420 | amdtemp_k8_setup_sensors(struct amdtemp_softc *sc, int dv_unit) | | 423 | amdtemp_k8_setup_sensors(struct amdtemp_softc *sc, int dv_unit) |
421 | { | | 424 | { |
422 | uint8_t i; | | 425 | uint8_t i; |
423 | | | 426 | |
424 | /* There are two sensors per CPU core. So we use the | | 427 | /* There are two sensors per CPU core. So we use the |
425 | * device unit as socket counter to correctly enumerate | | 428 | * device unit as socket counter to correctly enumerate |
426 | * the CPUs on multi-socket machines. | | 429 | * the CPUs on multi-socket machines. |
427 | */ | | 430 | */ |
428 | dv_unit *= (sc->sc_numsensors / 2); | | 431 | dv_unit *= (sc->sc_numsensors / 2); |
429 | for (i = 0; i < sc->sc_numsensors; i++) { | | 432 | for (i = 0; i < sc->sc_numsensors; i++) { |
430 | sc->sc_sensor[i].units = ENVSYS_STEMP; | | 433 | sc->sc_sensor[i].units = ENVSYS_STEMP; |
431 | sc->sc_sensor[i].state = ENVSYS_SVALID; | | 434 | sc->sc_sensor[i].state = ENVSYS_SVALID; |
432 | | | 435 | |
433 | snprintf(sc->sc_sensor[i].desc, sizeof(sc->sc_sensor[i].desc), | | 436 | snprintf(sc->sc_sensor[i].desc, sizeof(sc->sc_sensor[i].desc), |
434 | "CPU%u Sensor%u", dv_unit + (i / 2), i % 2); | | 437 | "CPU%u Sensor%u", dv_unit + (i / 2), i % 2); |
435 | } | | 438 | } |
436 | } | | 439 | } |
437 | | | 440 | |
438 | | | 441 | |
439 | static void | | 442 | static void |
440 | amdtemp_k8_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 443 | amdtemp_k8_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
441 | { | | 444 | { |
442 | struct amdtemp_softc *sc = sme->sme_cookie; | | 445 | struct amdtemp_softc *sc = sme->sme_cookie; |
443 | pcireg_t status, match, tmp; | | 446 | pcireg_t status, match, tmp; |
444 | uint32_t value; | | 447 | uint32_t value; |
445 | | | 448 | |
446 | status = pci_conf_read(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R); | | 449 | status = pci_conf_read(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R); |
447 | | | 450 | |
448 | switch(edata->sensor) { /* sensor number */ | | 451 | switch(edata->sensor) { /* sensor number */ |
449 | case 0: /* Core 0 Sensor 0 */ | | 452 | case 0: /* Core 0 Sensor 0 */ |
450 | K8_T_SEL_C0(status); | | 453 | K8_T_SEL_C0(status); |
451 | K8_T_SEL_S0(status); | | 454 | K8_T_SEL_S0(status); |
452 | break; | | 455 | break; |
453 | case 1: /* Core 0 Sensor 1 */ | | 456 | case 1: /* Core 0 Sensor 1 */ |
454 | K8_T_SEL_C0(status); | | 457 | K8_T_SEL_C0(status); |
455 | K8_T_SEL_S1(status); | | 458 | K8_T_SEL_S1(status); |
456 | break; | | 459 | break; |
457 | case 2: /* Core 1 Sensor 0 */ | | 460 | case 2: /* Core 1 Sensor 0 */ |
458 | K8_T_SEL_C1(status); | | 461 | K8_T_SEL_C1(status); |
459 | K8_T_SEL_S0(status); | | 462 | K8_T_SEL_S0(status); |
460 | break; | | 463 | break; |
461 | case 3: /* Core 1 Sensor 1 */ | | 464 | case 3: /* Core 1 Sensor 1 */ |
462 | K8_T_SEL_C1(status); | | 465 | K8_T_SEL_C1(status); |
463 | K8_T_SEL_S1(status); | | 466 | K8_T_SEL_S1(status); |
464 | break; | | 467 | break; |
465 | } | | 468 | } |
466 | | | 469 | |
467 | match = status & (K8_THERM_SENSE_CORE_SEL | K8_THERM_SENSE_SEL); | | 470 | match = status & (K8_THERM_SENSE_CORE_SEL | K8_THERM_SENSE_SEL); |
468 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R, status); | | 471 | pci_conf_write(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R, status); |
469 | status = pci_conf_read(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R); | | 472 | status = pci_conf_read(sc->sc_pc, sc->sc_pcitag, THERMTRIP_STAT_R); |
470 | tmp = status & (K8_THERM_SENSE_CORE_SEL | K8_THERM_SENSE_SEL); | | 473 | tmp = status & (K8_THERM_SENSE_CORE_SEL | K8_THERM_SENSE_SEL); |
471 | | | 474 | |
472 | value = 0x3ff & (status >> 14); | | 475 | value = 0x3ff & (status >> 14); |
473 | if (sc->sc_rev != 'G') | | 476 | if (sc->sc_rev != 'G') |
474 | value &= ~0x3; | | 477 | value &= ~0x3; |
475 | | | 478 | |
476 | edata->state = ENVSYS_SINVALID; | | 479 | edata->state = ENVSYS_SINVALID; |
477 | if ((tmp == match) && ((value & ~0x3) != 0)) { | | 480 | if ((tmp == match) && ((value & ~0x3) != 0)) { |
478 | edata->state = ENVSYS_SVALID; | | 481 | edata->state = ENVSYS_SVALID; |
479 | edata->value_cur = (value * 250000 - 49000000) + 273150000 | | 482 | edata->value_cur = (value * 250000 - 49000000) + 273150000 |
480 | + sc->sc_adjustment; | | 483 | + sc->sc_adjustment; |
481 | } | | 484 | } |
482 | } | | 485 | } |
483 | | | 486 | |
484 | | | 487 | |
485 | static void | | 488 | static void |
486 | amdtemp_family10_init(struct amdtemp_softc *sc) | | 489 | amdtemp_family10_init(struct amdtemp_softc *sc) |
487 | { | | 490 | { |
488 | aprint_normal(" (Family%02xh)", sc->sc_family); | | 491 | aprint_normal(" (Family%02xh)", sc->sc_family); |
489 | | | 492 | |
490 | sc->sc_numsensors = 1; | | 493 | sc->sc_numsensors = 1; |
491 | } | | 494 | } |
492 | | | 495 | |
493 | static void | | 496 | static void |
494 | amdtemp_family10_setup_sensors(struct amdtemp_softc *sc, int dv_unit) | | 497 | amdtemp_family10_setup_sensors(struct amdtemp_softc *sc, int dv_unit) |
495 | { | | 498 | { |
496 | /* sanity check for future enhancements */ | | 499 | /* sanity check for future enhancements */ |
497 | KASSERT(sc->sc_numsensors == 1); | | 500 | KASSERT(sc->sc_numsensors == 1); |
498 | | | 501 | |
499 | /* There's one sensor per memory controller (= socket) | | 502 | /* There's one sensor per memory controller (= socket) |
500 | * so we use the device unit as socket counter | | 503 | * so we use the device unit as socket counter |
501 | * to correctly enumerate the CPUs | | 504 | * to correctly enumerate the CPUs |
502 | */ | | 505 | */ |
503 | sc->sc_sensor[0].units = ENVSYS_STEMP; | | 506 | sc->sc_sensor[0].units = ENVSYS_STEMP; |
504 | sc->sc_sensor[0].state = ENVSYS_SVALID; | | 507 | sc->sc_sensor[0].state = ENVSYS_SVALID; |
505 | | | 508 | |
506 | snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc), | | 509 | snprintf(sc->sc_sensor[0].desc, sizeof(sc->sc_sensor[0].desc), |
507 | "cpu%u temperature", dv_unit); | | 510 | "cpu%u temperature", dv_unit); |
508 | } | | 511 | } |
509 | | | 512 | |
510 | | | 513 | |
511 | static void | | 514 | static void |
512 | amdtemp_family10_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) | | 515 | amdtemp_family10_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) |
513 | { | | 516 | { |
514 | struct amdtemp_softc *sc = sme->sme_cookie; | | 517 | struct amdtemp_softc *sc = sme->sme_cookie; |
515 | pcireg_t status; | | 518 | pcireg_t status; |
516 | uint32_t value; | | 519 | uint32_t value; |
517 | | | 520 | |
518 | status = pci_conf_read(sc->sc_pc, | | 521 | status = pci_conf_read(sc->sc_pc, |
519 | sc->sc_pcitag, F10_TEMPERATURE_CTL_R); | | 522 | sc->sc_pcitag, F10_TEMPERATURE_CTL_R); |
520 | | | 523 | |
521 | value = (status >> 21); | | 524 | value = (status >> 21); |
522 | | | 525 | |
523 | edata->state = ENVSYS_SVALID; | | 526 | edata->state = ENVSYS_SVALID; |
524 | edata->value_cur = (value * 125000) + 273150000; /* From C to uK. */ | | 527 | edata->value_cur = (value * 125000) + 273150000; /* From C to uK. */ |
525 | } | | 528 | } |
526 | | | 529 | |
527 | MODULE(MODULE_CLASS_DRIVER, amdtemp, NULL); | | 530 | MODULE(MODULE_CLASS_DRIVER, amdtemp, NULL); |
528 | | | 531 | |
529 | #ifdef _MODULE | | 532 | #ifdef _MODULE |
530 | #include "ioconf.c" | | 533 | #include "ioconf.c" |
531 | #endif | | 534 | #endif |
532 | | | 535 | |
533 | static int | | 536 | static int |
534 | amdtemp_modcmd(modcmd_t cmd, void *aux) | | 537 | amdtemp_modcmd(modcmd_t cmd, void *aux) |
535 | { | | 538 | { |
536 | int error = 0; | | 539 | int error = 0; |
537 | | | 540 | |
538 | switch (cmd) { | | 541 | switch (cmd) { |
539 | case MODULE_CMD_INIT: | | 542 | case MODULE_CMD_INIT: |
540 | #ifdef _MODULE | | 543 | #ifdef _MODULE |
541 | error = config_init_component(cfdriver_ioconf_amdtemp, | | 544 | error = config_init_component(cfdriver_ioconf_amdtemp, |
542 | cfattach_ioconf_amdtemp, cfdata_ioconf_amdtemp); | | 545 | cfattach_ioconf_amdtemp, cfdata_ioconf_amdtemp); |
543 | #endif | | 546 | #endif |
544 | return error; | | 547 | return error; |
545 | case MODULE_CMD_FINI: | | 548 | case MODULE_CMD_FINI: |
546 | #ifdef _MODULE | | 549 | #ifdef _MODULE |
547 | error = config_fini_component(cfdriver_ioconf_amdtemp, | | 550 | error = config_fini_component(cfdriver_ioconf_amdtemp, |
548 | cfattach_ioconf_amdtemp, cfdata_ioconf_amdtemp); | | 551 | cfattach_ioconf_amdtemp, cfdata_ioconf_amdtemp); |
549 | #endif | | 552 | #endif |
550 | return error; | | 553 | return error; |
551 | default: | | 554 | default: |
552 | return ENOTTY; | | 555 | return ENOTTY; |
553 | } | | 556 | } |
554 | } | | 557 | } |