File: | dev/acpi/acpicpu.c |
Warning: | line 1200, column 2 Access to field 'state' results in a dereference of a null pointer (loaded from variable 'best') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: acpicpu.c,v 1.91 2022/01/09 05:42:37 jsg Exp $ */ | |||
2 | /* | |||
3 | * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> | |||
4 | * Copyright (c) 2015 Philip Guenther <guenther@openbsd.org> | |||
5 | * | |||
6 | * Permission to use, copy, modify, and distribute this software for any | |||
7 | * purpose with or without fee is hereby granted, provided that the above | |||
8 | * copyright notice and this permission notice appear in all copies. | |||
9 | * | |||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
17 | */ | |||
18 | ||||
19 | #include <sys/param.h> | |||
20 | #include <sys/kernel.h> /* for tick */ | |||
21 | #include <sys/signalvar.h> | |||
22 | #include <sys/sysctl.h> | |||
23 | #include <sys/systm.h> | |||
24 | #include <sys/device.h> | |||
25 | #include <sys/malloc.h> | |||
26 | #include <sys/queue.h> | |||
27 | #include <sys/atomic.h> | |||
28 | ||||
29 | #include <machine/bus.h> | |||
30 | #include <machine/cpu.h> | |||
31 | #include <machine/cpufunc.h> | |||
32 | #include <machine/specialreg.h> | |||
33 | ||||
34 | #include <dev/acpi/acpireg.h> | |||
35 | #include <dev/acpi/acpivar.h> | |||
36 | #include <dev/acpi/acpidev.h> | |||
37 | #include <dev/acpi/amltypes.h> | |||
38 | #include <dev/acpi/dsdt.h> | |||
39 | ||||
40 | #include <sys/sensors.h> | |||
41 | ||||
42 | int acpicpu_match(struct device *, void *, void *); | |||
43 | void acpicpu_attach(struct device *, struct device *, void *); | |||
44 | int acpicpu_notify(struct aml_node *, int, void *); | |||
45 | void acpicpu_setperf(int); | |||
46 | void acpicpu_setperf_ppc_change(struct acpicpu_pss *, int); | |||
47 | ||||
48 | #define ACPI_STATE_C00x00 0x00 | |||
49 | #define ACPI_STATE_C10x01 0x01 | |||
50 | #define ACPI_STATE_C20x02 0x02 | |||
51 | #define ACPI_STATE_C30x03 0x03 | |||
52 | ||||
53 | #define ACPI_PDC_REVID0x1 0x1 | |||
54 | #define ACPI_PDC_SMP0xa 0xa | |||
55 | #define ACPI_PDC_MSR0x1 0x1 | |||
56 | ||||
57 | /* _PDC/_OSC Intel capabilities flags */ | |||
58 | #define ACPI_PDC_P_FFH0x0001 0x0001 | |||
59 | #define ACPI_PDC_C_C1_HALT0x0002 0x0002 | |||
60 | #define ACPI_PDC_T_FFH0x0004 0x0004 | |||
61 | #define ACPI_PDC_SMP_C1PT0x0008 0x0008 | |||
62 | #define ACPI_PDC_SMP_C2C30x0010 0x0010 | |||
63 | #define ACPI_PDC_SMP_P_SWCOORD0x0020 0x0020 | |||
64 | #define ACPI_PDC_SMP_C_SWCOORD0x0040 0x0040 | |||
65 | #define ACPI_PDC_SMP_T_SWCOORD0x0080 0x0080 | |||
66 | #define ACPI_PDC_C_C1_FFH0x0100 0x0100 | |||
67 | #define ACPI_PDC_C_C2C3_FFH0x0200 0x0200 | |||
68 | /* reserved 0x0400 */ | |||
69 | #define ACPI_PDC_P_HWCOORD0x0800 0x0800 | |||
70 | #define ACPI_PDC_PPC_NOTIFY0x1000 0x1000 | |||
71 | ||||
72 | #define CST_METH_HALT0 0 | |||
73 | #define CST_METH_IO_HALT1 1 | |||
74 | #define CST_METH_MWAIT2 2 | |||
75 | #define CST_METH_GAS_IO3 3 | |||
76 | ||||
77 | /* flags on Intel's FFH mwait method */ | |||
78 | #define CST_FLAG_MWAIT_HW_COORD0x1 0x1 | |||
79 | #define CST_FLAG_MWAIT_BM_AVOIDANCE0x2 0x2 | |||
80 | #define CST_FLAG_FALLBACK0x4000 0x4000 /* fallback for broken _CST */ | |||
81 | #define CST_FLAG_SKIP0x8000 0x8000 /* state is worse choice */ | |||
82 | ||||
83 | #define FLAGS_MWAIT_ONLY0x02 0x02 | |||
84 | #define FLAGS_BMCHECK0x04 0x04 | |||
85 | #define FLAGS_NOTHROTTLE0x08 0x08 | |||
86 | #define FLAGS_NOPSS0x10 0x10 | |||
87 | #define FLAGS_NOPCT0x20 0x20 | |||
88 | ||||
89 | #define CPU_THT_EN(1L << 4) (1L << 4) | |||
90 | #define CPU_MAXSTATE(sc)(1L << (sc)->sc_duty_wid) (1L << (sc)->sc_duty_wid) | |||
91 | #define CPU_STATE(sc,pct)((pct * (1L << (sc)->sc_duty_wid) / 100) << (sc )->sc_duty_off) ((pct * CPU_MAXSTATE(sc)(1L << (sc)->sc_duty_wid) / 100) << (sc)->sc_duty_off) | |||
92 | #define CPU_STATEMASK(sc)(((1L << (sc)->sc_duty_wid) - 1) << (sc)->sc_duty_off ) ((CPU_MAXSTATE(sc)(1L << (sc)->sc_duty_wid) - 1) << (sc)->sc_duty_off) | |||
93 | ||||
94 | #define ACPI_MAX_C2_LATENCY100 100 | |||
95 | #define ACPI_MAX_C3_LATENCY1000 1000 | |||
96 | ||||
97 | #define CSD_COORD_SW_ALL0xFC 0xFC | |||
98 | #define CSD_COORD_SW_ANY0xFD 0xFD | |||
99 | #define CSD_COORD_HW_ALL0xFE 0xFE | |||
100 | ||||
101 | /* Make sure throttling bits are valid,a=addr,o=offset,w=width */ | |||
102 | #define valid_throttle(o,w,a)(a && w && (o+w)<=31 && (o>4 || (o+w)<=4)) (a && w && (o+w)<=31 && (o>4 || (o+w)<=4)) | |||
103 | ||||
104 | struct acpi_cstate | |||
105 | { | |||
106 | SLIST_ENTRY(acpi_cstate)struct { struct acpi_cstate *sle_next; } link; | |||
107 | ||||
108 | u_short state; | |||
109 | short method; /* CST_METH_* */ | |||
110 | u_short flags; /* CST_FLAG_* */ | |||
111 | u_short latency; | |||
112 | int power; | |||
113 | uint64_t address; /* or mwait hint */ | |||
114 | }; | |||
115 | ||||
116 | unsigned long cst_stats[4] = { 0 }; | |||
117 | ||||
118 | struct acpicpu_softc { | |||
119 | struct device sc_dev; | |||
120 | int sc_cpu; | |||
121 | ||||
122 | int sc_duty_wid; | |||
123 | int sc_duty_off; | |||
124 | uint32_t sc_pblk_addr; | |||
125 | int sc_pblk_len; | |||
126 | int sc_flags; | |||
127 | unsigned long sc_prev_sleep; | |||
128 | unsigned long sc_last_itime; | |||
129 | ||||
130 | struct cpu_info *sc_ci; | |||
131 | SLIST_HEAD(,acpi_cstate)struct { struct acpi_cstate *slh_first; } sc_cstates; | |||
132 | ||||
133 | bus_space_tag_t sc_iot; | |||
134 | bus_space_handle_t sc_ioh; | |||
135 | ||||
136 | struct acpi_softc *sc_acpi; | |||
137 | struct aml_node *sc_devnode; | |||
138 | ||||
139 | int sc_pss_len; /* XXX */ | |||
140 | int sc_ppc; | |||
141 | int sc_level; | |||
142 | struct acpicpu_pss *sc_pss; | |||
143 | size_t sc_pssfulllen; | |||
144 | ||||
145 | struct acpicpu_pct sc_pct; | |||
146 | /* save compensation for pct access for lying bios' */ | |||
147 | uint32_t sc_pct_stat_as; | |||
148 | uint32_t sc_pct_ctrl_as; | |||
149 | uint32_t sc_pct_stat_len; | |||
150 | uint32_t sc_pct_ctrl_len; | |||
151 | /* | |||
152 | * XXX: _PPC Change listener | |||
153 | * PPC changes can occur when for example a machine is disconnected | |||
154 | * from AC power and can no longer support the highest frequency or | |||
155 | * voltage when driven from the battery. | |||
156 | * Should probably be reimplemented as a list for now we assume only | |||
157 | * one listener | |||
158 | */ | |||
159 | void (*sc_notify)(struct acpicpu_pss *, int); | |||
160 | }; | |||
161 | ||||
162 | void acpicpu_add_cstatepkg(struct aml_value *, void *); | |||
163 | void acpicpu_add_cdeppkg(struct aml_value *, void *); | |||
164 | int acpicpu_getppc(struct acpicpu_softc *); | |||
165 | int acpicpu_getpct(struct acpicpu_softc *); | |||
166 | int acpicpu_getpss(struct acpicpu_softc *); | |||
167 | int acpicpu_getcst(struct acpicpu_softc *); | |||
168 | void acpicpu_getcst_from_fadt(struct acpicpu_softc *); | |||
169 | void acpicpu_print_one_cst(struct acpi_cstate *_cx); | |||
170 | void acpicpu_print_cst(struct acpicpu_softc *_sc); | |||
171 | void acpicpu_add_cstate(struct acpicpu_softc *_sc, int _state, int _method, | |||
172 | int _flags, int _latency, int _power, uint64_t _address); | |||
173 | void acpicpu_set_pdc(struct acpicpu_softc *); | |||
174 | void acpicpu_idle(void); | |||
175 | ||||
176 | #if 0 | |||
177 | void acpicpu_set_throttle(struct acpicpu_softc *, int); | |||
178 | struct acpi_cstate *acpicpu_find_cstate(struct acpicpu_softc *, int); | |||
179 | #endif | |||
180 | ||||
181 | struct cfattach acpicpu_ca = { | |||
182 | sizeof(struct acpicpu_softc), acpicpu_match, acpicpu_attach | |||
183 | }; | |||
184 | ||||
185 | struct cfdriver acpicpu_cd = { | |||
186 | NULL((void *)0), "acpicpu", DV_DULL | |||
187 | }; | |||
188 | ||||
189 | const char *acpicpu_hids[] = { | |||
190 | "ACPI0007", | |||
191 | NULL((void *)0) | |||
192 | }; | |||
193 | ||||
194 | extern int setperf_prio; | |||
195 | ||||
196 | #if 0 | |||
197 | void | |||
198 | acpicpu_set_throttle(struct acpicpu_softc *sc, int level) | |||
199 | { | |||
200 | uint32_t pbval; | |||
201 | ||||
202 | if (sc->sc_flags & FLAGS_NOTHROTTLE0x08) | |||
203 | return; | |||
204 | ||||
205 | /* Disable throttling control */ | |||
206 | pbval = inl(sc->sc_pblk_addr)( (__builtin_constant_p((sc->sc_pblk_addr)) && (sc ->sc_pblk_addr) < 0x100) ? __inlc(sc->sc_pblk_addr) : __inl(sc->sc_pblk_addr)); | |||
207 | outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN)( (__builtin_constant_p((sc->sc_pblk_addr)) && (sc ->sc_pblk_addr) < 0x100) ? __outlc(sc->sc_pblk_addr, pbval & ~(1L << 4)) : __outl(sc->sc_pblk_addr, pbval & ~(1L << 4))); | |||
208 | if (level < 100) { | |||
209 | pbval &= ~CPU_STATEMASK(sc)(((1L << (sc)->sc_duty_wid) - 1) << (sc)->sc_duty_off ); | |||
210 | pbval |= CPU_STATE(sc, level)((level * (1L << (sc)->sc_duty_wid) / 100) << ( sc)->sc_duty_off); | |||
211 | outl(sc->sc_pblk_addr, pbval & ~CPU_THT_EN)( (__builtin_constant_p((sc->sc_pblk_addr)) && (sc ->sc_pblk_addr) < 0x100) ? __outlc(sc->sc_pblk_addr, pbval & ~(1L << 4)) : __outl(sc->sc_pblk_addr, pbval & ~(1L << 4))); | |||
212 | outl(sc->sc_pblk_addr, pbval | CPU_THT_EN)( (__builtin_constant_p((sc->sc_pblk_addr)) && (sc ->sc_pblk_addr) < 0x100) ? __outlc(sc->sc_pblk_addr, pbval | (1L << 4)) : __outl(sc->sc_pblk_addr, pbval | (1L << 4))); | |||
213 | } | |||
214 | } | |||
215 | ||||
216 | struct acpi_cstate * | |||
217 | acpicpu_find_cstate(struct acpicpu_softc *sc, int state) | |||
218 | { | |||
219 | struct acpi_cstate *cx; | |||
220 | ||||
221 | SLIST_FOREACH(cx, &sc->sc_cstates, link)for((cx) = ((&sc->sc_cstates)->slh_first); (cx) != ( (void *)0); (cx) = ((cx)->link.sle_next)) | |||
222 | if (cx->state == state) | |||
223 | return cx; | |||
224 | return (NULL((void *)0)); | |||
225 | } | |||
226 | #endif | |||
227 | ||||
228 | ||||
229 | void | |||
230 | acpicpu_set_pdc(struct acpicpu_softc *sc) | |||
231 | { | |||
232 | struct aml_value cmd, osc_cmd[4]; | |||
233 | struct aml_value res; | |||
234 | uint32_t cap; | |||
235 | uint32_t buf[3]; | |||
236 | ||||
237 | /* 4077A616-290C-47BE-9EBD-D87058713953 */ | |||
238 | static uint8_t cpu_oscuuid[16] = { 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, | |||
239 | 0xBE, 0x47, 0x9E, 0xBD, 0xD8, 0x70, | |||
240 | 0x58, 0x71, 0x39, 0x53 }; | |||
241 | cap = ACPI_PDC_C_C1_HALT0x0002 | ACPI_PDC_P_FFH0x0001 | ACPI_PDC_C_C1_FFH0x0100 | |||
242 | | ACPI_PDC_C_C2C3_FFH0x0200 | ACPI_PDC_SMP_P_SWCOORD0x0020 | ACPI_PDC_SMP_C2C30x0010 | |||
243 | | ACPI_PDC_SMP_C1PT0x0008; | |||
244 | ||||
245 | if (aml_searchname(sc->sc_devnode, "_OSC")) { | |||
246 | /* Query _OSC */ | |||
247 | memset(&osc_cmd, 0, sizeof(osc_cmd))__builtin_memset((&osc_cmd), (0), (sizeof(osc_cmd))); | |||
248 | osc_cmd[0].type = AML_OBJTYPE_BUFFER; | |||
249 | osc_cmd[0].v_buffer_.vbuffer = (uint8_t *)&cpu_oscuuid; | |||
250 | osc_cmd[0].length = sizeof(cpu_oscuuid); | |||
251 | ||||
252 | osc_cmd[1].type = AML_OBJTYPE_INTEGER; | |||
253 | osc_cmd[1].v_integer_.vinteger = 1; | |||
254 | osc_cmd[1].length = 1; | |||
255 | ||||
256 | osc_cmd[2].type = AML_OBJTYPE_INTEGER; | |||
257 | osc_cmd[2].v_integer_.vinteger = 2; | |||
258 | osc_cmd[2].length = 1; | |||
259 | ||||
260 | buf[0] = 1; | |||
261 | buf[1] = cap; | |||
262 | osc_cmd[3].type = AML_OBJTYPE_BUFFER; | |||
263 | osc_cmd[3].v_buffer_.vbuffer = (int8_t *)&buf; | |||
264 | osc_cmd[3].length = sizeof(buf); | |||
265 | ||||
266 | aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OSC", | |||
267 | 4, osc_cmd, &res); | |||
268 | ||||
269 | if (res.type != AML_OBJTYPE_BUFFER || res.length < 8) { | |||
270 | printf(": unable to query capabilities\n"); | |||
271 | aml_freevalue(&res); | |||
272 | return; | |||
273 | } | |||
274 | ||||
275 | /* Evaluate _OSC */ | |||
276 | memset(&osc_cmd, 0, sizeof(osc_cmd))__builtin_memset((&osc_cmd), (0), (sizeof(osc_cmd))); | |||
277 | osc_cmd[0].type = AML_OBJTYPE_BUFFER; | |||
278 | osc_cmd[0].v_buffer_.vbuffer = (uint8_t *)&cpu_oscuuid; | |||
279 | osc_cmd[0].length = sizeof(cpu_oscuuid); | |||
280 | ||||
281 | osc_cmd[1].type = AML_OBJTYPE_INTEGER; | |||
282 | osc_cmd[1].v_integer_.vinteger = 1; | |||
283 | osc_cmd[1].length = 1; | |||
284 | ||||
285 | osc_cmd[2].type = AML_OBJTYPE_INTEGER; | |||
286 | osc_cmd[2].v_integer_.vinteger = 2; | |||
287 | osc_cmd[2].length = 1; | |||
288 | ||||
289 | buf[0] = 0; | |||
290 | buf[1] = (*(uint32_t *)&res.v_buffer_.vbuffer[4]) & cap; | |||
291 | osc_cmd[3].type = AML_OBJTYPE_BUFFER; | |||
292 | osc_cmd[3].v_buffer_.vbuffer = (int8_t *)&buf; | |||
293 | osc_cmd[3].length = sizeof(buf); | |||
294 | ||||
295 | aml_freevalue(&res); | |||
296 | ||||
297 | aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OSC", | |||
298 | 4, osc_cmd, NULL((void *)0)); | |||
299 | } else { | |||
300 | /* Evaluate _PDC */ | |||
301 | memset(&cmd, 0, sizeof(cmd))__builtin_memset((&cmd), (0), (sizeof(cmd))); | |||
302 | cmd.type = AML_OBJTYPE_BUFFER; | |||
303 | cmd.v_buffer_.vbuffer = (uint8_t *)&buf; | |||
304 | cmd.length = sizeof(buf); | |||
305 | ||||
306 | buf[0] = ACPI_PDC_REVID0x1; | |||
307 | buf[1] = 1; | |||
308 | buf[2] = cap; | |||
309 | ||||
310 | aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PDC", | |||
311 | 1, &cmd, NULL((void *)0)); | |||
312 | } | |||
313 | } | |||
314 | ||||
315 | /* | |||
316 | * sanity check mwait hints against what cpuid told us | |||
317 | * ...but because intel screwed up, just check whether cpuid says | |||
318 | * the given state has _any_ substates. | |||
319 | */ | |||
320 | static int | |||
321 | check_mwait_hints(int state, int hints) | |||
322 | { | |||
323 | int cstate; | |||
324 | int num_substates; | |||
325 | ||||
326 | if (cpu_mwait_size == 0) | |||
327 | return (0); | |||
328 | cstate = ((hints >> 4) & 0xf) + 1; | |||
329 | if (cstate == 16) | |||
330 | cstate = 0; | |||
331 | else if (cstate > 7) { | |||
332 | /* out of range of test against CPUID; just trust'em */ | |||
333 | return (1); | |||
334 | } | |||
335 | num_substates = (cpu_mwait_states >> (4 * cstate)) & 0xf; | |||
336 | if (num_substates == 0) { | |||
337 | printf(": C%d bad (state %d has no substates)", state, cstate); | |||
338 | return (0); | |||
339 | } | |||
340 | return (1); | |||
341 | } | |||
342 | ||||
343 | void | |||
344 | acpicpu_add_cstate(struct acpicpu_softc *sc, int state, int method, | |||
345 | int flags, int latency, int power, uint64_t address) | |||
346 | { | |||
347 | struct acpi_cstate *cx; | |||
348 | ||||
349 | dnprintf(10," C%d: latency:.%4x power:%.4x addr:%.16llx\n", | |||
350 | state, latency, power, address); | |||
351 | ||||
352 | /* add a new state, or overwrite the fallback C1 state? */ | |||
353 | if (state != ACPI_STATE_C10x01 || | |||
354 | (cx = SLIST_FIRST(&sc->sc_cstates)((&sc->sc_cstates)->slh_first)) == NULL((void *)0) || | |||
355 | (cx->flags & CST_FLAG_FALLBACK0x4000) == 0) { | |||
356 | cx = malloc(sizeof(*cx), M_DEVBUF2, M_WAITOK0x0001); | |||
357 | SLIST_INSERT_HEAD(&sc->sc_cstates, cx, link)do { (cx)->link.sle_next = (&sc->sc_cstates)->slh_first ; (&sc->sc_cstates)->slh_first = (cx); } while (0); | |||
358 | } | |||
359 | ||||
360 | cx->state = state; | |||
361 | cx->method = method; | |||
362 | cx->flags = flags; | |||
363 | cx->latency = latency; | |||
364 | cx->power = power; | |||
365 | cx->address = address; | |||
366 | } | |||
367 | ||||
368 | /* Found a _CST object, add new cstate for each entry */ | |||
369 | void | |||
370 | acpicpu_add_cstatepkg(struct aml_value *val, void *arg) | |||
371 | { | |||
372 | struct acpicpu_softc *sc = arg; | |||
373 | uint64_t addr; | |||
374 | struct acpi_grd *grd; | |||
375 | int state, method, flags; | |||
376 | ||||
377 | #if defined(ACPI_DEBUG) && !defined(SMALL_KERNEL) | |||
378 | aml_showvalue(val); | |||
379 | #endif | |||
380 | if (val->type != AML_OBJTYPE_PACKAGE || val->length != 4) | |||
381 | return; | |||
382 | ||||
383 | /* range and sanity checks */ | |||
384 | state = val->v_package_.vpackage[1]->v_integer_.vinteger; | |||
385 | if (state < 0 || state > 4) | |||
386 | return; | |||
387 | if (val->v_package_.vpackage[0]->type != AML_OBJTYPE_BUFFER) { | |||
388 | printf(": C%d (unexpected ACPI object type %d)", | |||
389 | state, val->v_package_.vpackage[0]->type); | |||
390 | return; | |||
391 | } | |||
392 | grd = (struct acpi_grd *)val->v_package_.vpackage[0]->v_buffer_.vbuffer; | |||
393 | if (val->v_package_.vpackage[0]->length != sizeof(*grd) + 2 || | |||
394 | grd->grd_descriptor != LR_GENREGISTER0x82 || | |||
395 | grd->grd_length != sizeof(grd->grd_gas) || | |||
396 | val->v_package_.vpackage[0]->v_buffer_.vbuffer[sizeof(*grd)] != SRT_ENDTAG0x79) { | |||
397 | printf(": C%d (bogo buffer)", state); | |||
398 | return; | |||
399 | } | |||
400 | ||||
401 | flags = 0; | |||
402 | switch (grd->grd_gas.address_space_id) { | |||
403 | case GAS_FUNCTIONAL_FIXED127: | |||
404 | if (grd->grd_gas.register_bit_width == 0) { | |||
405 | method = CST_METH_HALT0; | |||
406 | addr = 0; | |||
407 | } else { | |||
408 | /* | |||
409 | * In theory we should only do this for | |||
410 | * vendor 1 == Intel but other values crop up, | |||
411 | * presumably due to the normal ACPI spec confusion. | |||
412 | */ | |||
413 | switch (grd->grd_gas.register_bit_offset) { | |||
414 | case 0x1: | |||
415 | method = CST_METH_IO_HALT1; | |||
416 | addr = grd->grd_gas.address; | |||
417 | ||||
418 | /* i386 and amd64 I/O space is 16bits */ | |||
419 | if (addr > 0xffff) { | |||
420 | printf(": C%d (bogo I/O addr %llx)", | |||
421 | state, addr); | |||
422 | return; | |||
423 | } | |||
424 | break; | |||
425 | case 0x2: | |||
426 | addr = grd->grd_gas.address; | |||
427 | if (!check_mwait_hints(state, addr)) | |||
428 | return; | |||
429 | method = CST_METH_MWAIT2; | |||
430 | flags = grd->grd_gas.access_size; | |||
431 | break; | |||
432 | default: | |||
433 | printf(": C%d (unknown FFH class %d)", | |||
434 | state, grd->grd_gas.register_bit_offset); | |||
435 | return; | |||
436 | } | |||
437 | } | |||
438 | break; | |||
439 | ||||
440 | case GAS_SYSTEM_IOSPACE1: | |||
441 | addr = grd->grd_gas.address; | |||
442 | if (grd->grd_gas.register_bit_width != 8 || | |||
443 | grd->grd_gas.register_bit_offset != 0) { | |||
444 | printf(": C%d (unhandled %s spec: %d/%d)", state, | |||
445 | "I/O", grd->grd_gas.register_bit_width, | |||
446 | grd->grd_gas.register_bit_offset); | |||
447 | return; | |||
448 | } | |||
449 | method = CST_METH_GAS_IO3; | |||
450 | break; | |||
451 | ||||
452 | default: | |||
453 | /* dump the GAS for analysis */ | |||
454 | { | |||
455 | int i; | |||
456 | printf(": C%d (unhandled GAS:", state); | |||
457 | for (i = 0; i < sizeof(grd->grd_gas); i++) | |||
458 | printf(" %#x", ((u_char *)&grd->grd_gas)[i]); | |||
459 | printf(")"); | |||
460 | ||||
461 | } | |||
462 | return; | |||
463 | } | |||
464 | ||||
465 | acpicpu_add_cstate(sc, state, method, flags, | |||
466 | val->v_package_.vpackage[2]->v_integer_.vinteger, val->v_package_.vpackage[3]->v_integer_.vinteger, addr); | |||
467 | } | |||
468 | ||||
469 | ||||
470 | /* Found a _CSD object, print the dependency */ | |||
471 | void | |||
472 | acpicpu_add_cdeppkg(struct aml_value *val, void *arg) | |||
473 | { | |||
474 | int64_t num_proc, coord_type, domain, cindex; | |||
475 | ||||
476 | /* | |||
477 | * errors: unexpected object type, bad length, mismatched length, | |||
478 | * and bad CSD revision | |||
479 | */ | |||
480 | if (val->type != AML_OBJTYPE_PACKAGE || val->length < 6 || | |||
481 | val->length != val->v_package_.vpackage[0]->v_integer_.vinteger || | |||
482 | val->v_package_.vpackage[1]->v_integer_.vinteger != 0) { | |||
483 | #if 1 || defined(ACPI_DEBUG) && !defined(SMALL_KERNEL) | |||
484 | aml_showvalue(val); | |||
485 | #endif | |||
486 | printf("bogus CSD\n"); | |||
487 | return; | |||
488 | } | |||
489 | ||||
490 | /* coordinating 'among' one CPU is trivial, ignore */ | |||
491 | num_proc = val->v_package_.vpackage[4]->v_integer_.vinteger; | |||
492 | if (num_proc == 1) | |||
493 | return; | |||
494 | ||||
495 | /* we practically assume the hardware will coordinate, so ignore */ | |||
496 | coord_type = val->v_package_.vpackage[3]->v_integer_.vinteger; | |||
497 | if (coord_type == CSD_COORD_HW_ALL0xFE) | |||
498 | return; | |||
499 | ||||
500 | domain = val->v_package_.vpackage[2]->v_integer_.vinteger; | |||
501 | cindex = val->v_package_.vpackage[5]->v_integer_.vinteger; | |||
502 | printf(": CSD (c=%#llx d=%lld n=%lld i=%lli)", | |||
503 | coord_type, domain, num_proc, cindex); | |||
504 | } | |||
505 | ||||
506 | int | |||
507 | acpicpu_getcst(struct acpicpu_softc *sc) | |||
508 | { | |||
509 | struct aml_value res; | |||
510 | struct acpi_cstate *cx, *next_cx; | |||
511 | int use_nonmwait; | |||
512 | ||||
513 | /* delete the existing list */ | |||
514 | while ((cx = SLIST_FIRST(&sc->sc_cstates)((&sc->sc_cstates)->slh_first)) != NULL((void *)0)) { | |||
515 | SLIST_REMOVE_HEAD(&sc->sc_cstates, link)do { (&sc->sc_cstates)->slh_first = (&sc->sc_cstates )->slh_first->link.sle_next; } while (0); | |||
516 | free(cx, M_DEVBUF2, sizeof(*cx)); | |||
517 | } | |||
518 | ||||
519 | /* provide a fallback C1-via-halt in case _CST's C1 is bogus */ | |||
520 | acpicpu_add_cstate(sc, ACPI_STATE_C10x01, CST_METH_HALT0, | |||
521 | CST_FLAG_FALLBACK0x4000, 1, -1, 0); | |||
522 | ||||
523 | if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CST", 0, NULL((void *)0), &res)) | |||
524 | return (1); | |||
525 | ||||
526 | aml_foreachpkg(&res, 1, acpicpu_add_cstatepkg, sc); | |||
527 | aml_freevalue(&res); | |||
528 | ||||
529 | /* only have fallback state? then no _CST objects were understood */ | |||
530 | cx = SLIST_FIRST(&sc->sc_cstates)((&sc->sc_cstates)->slh_first); | |||
531 | if (cx->flags & CST_FLAG_FALLBACK0x4000) | |||
532 | return (1); | |||
533 | ||||
534 | /* | |||
535 | * Skip states >= C2 if the CPU's LAPIC timer stops in deep | |||
536 | * states (i.e., it doesn't have the 'ARAT' bit set). | |||
537 | * Also keep track if all the states we'll use use mwait. | |||
538 | */ | |||
539 | use_nonmwait = 0; | |||
540 | while ((next_cx = SLIST_NEXT(cx, link)((cx)->link.sle_next)) != NULL((void *)0)) { | |||
541 | if (cx->state > 1 && | |||
542 | (sc->sc_ci->ci_feature_tpmflags & TPM_ARAT0x00000004) == 0) | |||
543 | cx->flags |= CST_FLAG_SKIP0x8000; | |||
544 | else if (cx->method != CST_METH_MWAIT2) | |||
545 | use_nonmwait = 1; | |||
546 | cx = next_cx; | |||
547 | } | |||
548 | if (use_nonmwait) | |||
549 | sc->sc_flags &= ~FLAGS_MWAIT_ONLY0x02; | |||
550 | else | |||
551 | sc->sc_flags |= FLAGS_MWAIT_ONLY0x02; | |||
552 | ||||
553 | if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CSD", 0, NULL((void *)0), &res)) { | |||
554 | aml_foreachpkg(&res, 1, acpicpu_add_cdeppkg, sc); | |||
555 | aml_freevalue(&res); | |||
556 | } | |||
557 | ||||
558 | return (0); | |||
559 | } | |||
560 | ||||
561 | /* | |||
562 | * old-style fixed C-state info in the FADT. | |||
563 | * Note that this has extra restrictions on values and flags. | |||
564 | */ | |||
565 | void | |||
566 | acpicpu_getcst_from_fadt(struct acpicpu_softc *sc) | |||
567 | { | |||
568 | struct acpi_fadt *fadt = sc->sc_acpi->sc_fadt; | |||
569 | int flags; | |||
570 | ||||
571 | /* FADT has to set flag to do C2 and higher on MP */ | |||
572 | if ((fadt->flags & FADT_P_LVL2_UP0x00000008) == 0 && ncpus > 1) | |||
573 | return; | |||
574 | ||||
575 | /* skip these C2 and C3 states if the CPU doesn't have ARAT */ | |||
576 | flags = (sc->sc_ci->ci_feature_tpmflags & TPM_ARAT0x00000004) | |||
577 | ? 0 : CST_FLAG_SKIP0x8000; | |||
578 | ||||
579 | /* Some systems don't export a full PBLK; reduce functionality */ | |||
580 | if (sc->sc_pblk_len >= 5 && fadt->p_lvl2_lat <= ACPI_MAX_C2_LATENCY100) { | |||
581 | acpicpu_add_cstate(sc, ACPI_STATE_C20x02, CST_METH_GAS_IO3, flags, | |||
582 | fadt->p_lvl2_lat, -1, sc->sc_pblk_addr + 4); | |||
583 | } | |||
584 | if (sc->sc_pblk_len >= 6 && fadt->p_lvl3_lat <= ACPI_MAX_C3_LATENCY1000) | |||
585 | acpicpu_add_cstate(sc, ACPI_STATE_C30x03, CST_METH_GAS_IO3, flags, | |||
586 | fadt->p_lvl3_lat, -1, sc->sc_pblk_addr + 5); | |||
587 | } | |||
588 | ||||
589 | ||||
590 | void | |||
591 | acpicpu_print_one_cst(struct acpi_cstate *cx) | |||
592 | { | |||
593 | const char *meth = ""; | |||
594 | int show_addr = 0; | |||
595 | ||||
596 | switch (cx->method) { | |||
597 | case CST_METH_IO_HALT1: | |||
598 | show_addr = 1; | |||
599 | /* fallthrough */ | |||
600 | case CST_METH_HALT0: | |||
601 | meth = " halt"; | |||
602 | break; | |||
603 | ||||
604 | case CST_METH_MWAIT2: | |||
605 | meth = " mwait"; | |||
606 | show_addr = cx->address != 0; | |||
607 | break; | |||
608 | ||||
609 | case CST_METH_GAS_IO3: | |||
610 | meth = " io"; | |||
611 | show_addr = 1; | |||
612 | break; | |||
613 | ||||
614 | } | |||
615 | ||||
616 | printf(" %sC%d(", (cx->flags & CST_FLAG_SKIP0x8000 ? "!" : ""), cx->state); | |||
617 | if (cx->power != -1) | |||
618 | printf("%d", cx->power); | |||
619 | printf("@%d%s", cx->latency, meth); | |||
620 | if (cx->flags & ~CST_FLAG_SKIP0x8000) { | |||
621 | if (cx->flags & CST_FLAG_FALLBACK0x4000) | |||
622 | printf("!"); | |||
623 | else | |||
624 | printf(".%x", (cx->flags & ~CST_FLAG_SKIP0x8000)); | |||
625 | } | |||
626 | if (show_addr) | |||
627 | printf("@0x%llx", cx->address); | |||
628 | printf(")"); | |||
629 | } | |||
630 | ||||
631 | void | |||
632 | acpicpu_print_cst(struct acpicpu_softc *sc) | |||
633 | { | |||
634 | struct acpi_cstate *cx; | |||
635 | int i; | |||
636 | ||||
637 | if (!SLIST_EMPTY(&sc->sc_cstates)(((&sc->sc_cstates)->slh_first) == ((void *)0))) { | |||
638 | printf(":"); | |||
639 | ||||
640 | i = 0; | |||
641 | SLIST_FOREACH(cx, &sc->sc_cstates, link)for((cx) = ((&sc->sc_cstates)->slh_first); (cx) != ( (void *)0); (cx) = ((cx)->link.sle_next)) { | |||
642 | if (i++) | |||
643 | printf(","); | |||
644 | acpicpu_print_one_cst(cx); | |||
645 | } | |||
646 | } | |||
647 | } | |||
648 | ||||
649 | ||||
650 | int | |||
651 | acpicpu_match(struct device *parent, void *match, void *aux) | |||
652 | { | |||
653 | struct acpi_attach_args *aa = aux; | |||
654 | struct cfdata *cf = match; | |||
655 | struct acpi_softc *acpi = (struct acpi_softc *)parent; | |||
656 | ||||
657 | if (acpi_matchhids(aa, acpicpu_hids, cf->cf_driver->cd_name) && | |||
658 | aa->aaa_node && aa->aaa_node->value && | |||
659 | aa->aaa_node->value->type == AML_OBJTYPE_DEVICE) { | |||
660 | /* | |||
661 | * Record that we've seen a Device() CPU object, | |||
662 | * so we won't attach any Processor() nodes. | |||
663 | */ | |||
664 | acpi->sc_skip_processor = 1; | |||
665 | return (1); | |||
666 | } | |||
667 | ||||
668 | /* sanity */ | |||
669 | if (aa->aaa_name == NULL((void *)0) || | |||
670 | strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || | |||
671 | aa->aaa_table != NULL((void *)0)) | |||
672 | return (0); | |||
673 | ||||
674 | return (1); | |||
675 | } | |||
676 | ||||
677 | void | |||
678 | acpicpu_attach(struct device *parent, struct device *self, void *aux) | |||
679 | { | |||
680 | struct acpicpu_softc *sc = (struct acpicpu_softc *)self; | |||
681 | struct acpi_attach_args *aa = aux; | |||
682 | struct aml_value res; | |||
683 | int64_t uid; | |||
684 | int i; | |||
685 | uint32_t status = 0; | |||
686 | CPU_INFO_ITERATORint cii; | |||
687 | struct cpu_info *ci; | |||
688 | ||||
689 | sc->sc_acpi = (struct acpi_softc *)parent; | |||
690 | sc->sc_devnode = aa->aaa_node; | |||
691 | ||||
692 | SLIST_INIT(&sc->sc_cstates){ ((&sc->sc_cstates)->slh_first) = ((void *)0); }; | |||
693 | ||||
694 | if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, | |||
695 | "_UID", 0, NULL((void *)0), &uid) == 0) | |||
696 | sc->sc_cpu = uid; | |||
697 | ||||
698 | if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL((void *)0), &res) == 0) { | |||
699 | if (res.type == AML_OBJTYPE_PROCESSOR) { | |||
700 | sc->sc_cpu = res.v_processor_.vprocessor.proc_id; | |||
701 | sc->sc_pblk_addr = res.v_processor_.vprocessor.proc_addr; | |||
702 | sc->sc_pblk_len = res.v_processor_.vprocessor.proc_len; | |||
703 | } | |||
704 | aml_freevalue(&res); | |||
705 | } | |||
706 | sc->sc_duty_off = sc->sc_acpi->sc_fadt->duty_offset; | |||
707 | sc->sc_duty_wid = sc->sc_acpi->sc_fadt->duty_width; | |||
708 | ||||
709 | /* link in the matching cpu_info */ | |||
710 | CPU_INFO_FOREACH(cii, ci)for (cii = 0, ci = cpu_info_list; ci != ((void *)0); ci = ci-> ci_next) | |||
711 | if (ci->ci_acpi_proc_id == sc->sc_cpu) { | |||
712 | ci->ci_acpicpudev = self; | |||
713 | sc->sc_ci = ci; | |||
714 | break; | |||
715 | } | |||
716 | if (ci == NULL((void *)0)) { | |||
717 | printf(": no cpu matching ACPI ID %d\n", sc->sc_cpu); | |||
718 | return; | |||
719 | } | |||
720 | ||||
721 | sc->sc_prev_sleep = 1000000; | |||
722 | ||||
723 | acpicpu_set_pdc(sc); | |||
724 | ||||
725 | if (!valid_throttle(sc->sc_duty_off, sc->sc_duty_wid, sc->sc_pblk_addr)(sc->sc_pblk_addr && sc->sc_duty_wid && (sc->sc_duty_off+sc->sc_duty_wid)<=31 && (sc ->sc_duty_off>4 || (sc->sc_duty_off+sc->sc_duty_wid )<=4))) | |||
726 | sc->sc_flags |= FLAGS_NOTHROTTLE0x08; | |||
727 | #ifdef ACPI_DEBUG | |||
728 | printf(": %s: ", sc->sc_devnode->name); | |||
729 | printf("\n: hdr:%x pblk:%x,%x duty:%x,%x pstate:%x " | |||
730 | "(%ld throttling states)\n", sc->sc_acpi->sc_fadt->hdr_revisionhdr.revision, | |||
731 | sc->sc_pblk_addr, sc->sc_pblk_len, sc->sc_duty_off, | |||
732 | sc->sc_duty_wid, sc->sc_acpi->sc_fadt->pstate_cnt, | |||
733 | CPU_MAXSTATE(sc)(1L << (sc)->sc_duty_wid)); | |||
734 | #endif | |||
735 | ||||
736 | /* Get C-States from _CST or FADT */ | |||
737 | if (acpicpu_getcst(sc) || SLIST_EMPTY(&sc->sc_cstates)(((&sc->sc_cstates)->slh_first) == ((void *)0))) | |||
738 | acpicpu_getcst_from_fadt(sc); | |||
739 | else { | |||
740 | /* Notify BIOS we use _CST objects */ | |||
741 | if (sc->sc_acpi->sc_fadt->cst_cnt) { | |||
742 | acpi_write_pmreg(sc->sc_acpi, ACPIREG_SMICMD0x0C, 0, | |||
743 | sc->sc_acpi->sc_fadt->cst_cnt); | |||
744 | } | |||
745 | } | |||
746 | if (!SLIST_EMPTY(&sc->sc_cstates)(((&sc->sc_cstates)->slh_first) == ((void *)0))) { | |||
747 | extern uint32_t acpi_force_bm; | |||
748 | ||||
749 | cpu_idle_cycle_fcn = &acpicpu_idle; | |||
750 | ||||
751 | /* | |||
752 | * C3 (and maybe C2?) needs BM_RLD to be set to | |||
753 | * wake the system | |||
754 | */ | |||
755 | if (SLIST_FIRST(&sc->sc_cstates)((&sc->sc_cstates)->slh_first)->state > 1 && acpi_force_bm == 0) { | |||
756 | uint16_t en = acpi_read_pmreg(sc->sc_acpi, | |||
757 | ACPIREG_PM1_CNT0x10, 0); | |||
758 | if ((en & ACPI_PM1_BM_RLD0x0002) == 0) { | |||
759 | acpi_write_pmreg(sc->sc_acpi, ACPIREG_PM1_CNT0x10, | |||
760 | 0, en | ACPI_PM1_BM_RLD0x0002); | |||
761 | acpi_force_bm = ACPI_PM1_BM_RLD0x0002; | |||
762 | } | |||
763 | } | |||
764 | } | |||
765 | ||||
766 | if (acpicpu_getpss(sc)) { | |||
767 | sc->sc_flags |= FLAGS_NOPSS0x10; | |||
768 | } else { | |||
769 | #ifdef ACPI_DEBUG | |||
770 | for (i = 0; i < sc->sc_pss_len; i++) { | |||
771 | dnprintf(20, "%d %d %d %d %d %d\n", | |||
772 | sc->sc_pss[i].pss_core_freq, | |||
773 | sc->sc_pss[i].pss_power, | |||
774 | sc->sc_pss[i].pss_trans_latency, | |||
775 | sc->sc_pss[i].pss_bus_latency, | |||
776 | sc->sc_pss[i].pss_ctrl, | |||
777 | sc->sc_pss[i].pss_status); | |||
778 | } | |||
779 | dnprintf(20, "\n"); | |||
780 | #endif | |||
781 | if (sc->sc_pss_len == 0) { | |||
782 | /* this should never happen */ | |||
783 | printf("%s: invalid _PSS length\n", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
784 | sc->sc_flags |= FLAGS_NOPSS0x10; | |||
785 | } | |||
786 | ||||
787 | acpicpu_getppc(sc); | |||
788 | if (acpicpu_getpct(sc)) | |||
789 | sc->sc_flags |= FLAGS_NOPCT0x20; | |||
790 | else if (sc->sc_pss_len > 0) { | |||
791 | /* Notify BIOS we are handling p-states */ | |||
792 | if (sc->sc_acpi->sc_fadt->pstate_cnt) { | |||
793 | acpi_write_pmreg(sc->sc_acpi, ACPIREG_SMICMD0x0C, | |||
794 | 0, sc->sc_acpi->sc_fadt->pstate_cnt); | |||
795 | } | |||
796 | ||||
797 | aml_register_notify(sc->sc_devnode, NULL((void *)0), | |||
798 | acpicpu_notify, sc, ACPIDEV_NOPOLL0); | |||
799 | ||||
800 | acpi_gasio(sc->sc_acpi, ACPI_IOREAD0, | |||
801 | sc->sc_pct.pct_status.grd_gas.address_space_id, | |||
802 | sc->sc_pct.pct_status.grd_gas.address, | |||
803 | sc->sc_pct_stat_as, sc->sc_pct_stat_as, &status); | |||
804 | sc->sc_level = (100 / sc->sc_pss_len) * | |||
805 | (sc->sc_pss_len - status); | |||
806 | dnprintf(20, "%s: cpu index %d, percentage %d\n", | |||
807 | DEVNAME(sc), status, sc->sc_level); | |||
808 | if (setperf_prio < 30) { | |||
809 | cpu_setperf = acpicpu_setperf; | |||
810 | acpicpu_set_notify(acpicpu_setperf_ppc_change); | |||
811 | setperf_prio = 30; | |||
812 | acpi_hasprocfvs = 1; | |||
813 | } | |||
814 | } | |||
815 | } | |||
816 | ||||
817 | /* | |||
818 | * Nicely enumerate what power management capabilities | |||
819 | * ACPI CPU provides. | |||
820 | */ | |||
821 | acpicpu_print_cst(sc); | |||
822 | if (!(sc->sc_flags & (FLAGS_NOPSS0x10 | FLAGS_NOPCT0x20)) || | |||
823 | !(sc->sc_flags & FLAGS_NOPSS0x10)) { | |||
824 | printf("%c ", SLIST_EMPTY(&sc->sc_cstates)(((&sc->sc_cstates)->slh_first) == ((void *)0)) ? ':' : ','); | |||
825 | ||||
826 | /* | |||
827 | * If acpicpu is itself providing the capability to transition | |||
828 | * states, enumerate them in the fashion that est and powernow | |||
829 | * would. | |||
830 | */ | |||
831 | if (!(sc->sc_flags & (FLAGS_NOPSS0x10 | FLAGS_NOPCT0x20))) { | |||
832 | printf("FVS, "); | |||
833 | for (i = 0; i < sc->sc_pss_len - 1; i++) | |||
834 | printf("%d, ", sc->sc_pss[i].pss_core_freq); | |||
835 | printf("%d MHz", sc->sc_pss[i].pss_core_freq); | |||
836 | } else | |||
837 | printf("PSS"); | |||
838 | } | |||
839 | ||||
840 | printf("\n"); | |||
841 | } | |||
842 | ||||
843 | int | |||
844 | acpicpu_getppc(struct acpicpu_softc *sc) | |||
845 | { | |||
846 | struct aml_value res; | |||
847 | ||||
848 | sc->sc_ppc = 0; | |||
849 | ||||
850 | if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PPC", 0, NULL((void *)0), &res)) { | |||
851 | dnprintf(10, "%s: no _PPC\n", DEVNAME(sc)); | |||
852 | return (1); | |||
853 | } | |||
854 | ||||
855 | sc->sc_ppc = aml_val2int(&res); | |||
856 | dnprintf(10, "%s: _PPC: %d\n", DEVNAME(sc), sc->sc_ppc); | |||
857 | aml_freevalue(&res); | |||
858 | ||||
859 | return (0); | |||
860 | } | |||
861 | ||||
862 | int | |||
863 | acpicpu_getpct(struct acpicpu_softc *sc) | |||
864 | { | |||
865 | struct aml_value res; | |||
866 | int rv = 1; | |||
867 | ||||
868 | if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PCT", 0, NULL((void *)0), &res)) { | |||
869 | dnprintf(20, "%s: no _PCT\n", DEVNAME(sc)); | |||
870 | return (1); | |||
871 | } | |||
872 | ||||
873 | if (res.length != 2) { | |||
874 | dnprintf(20, "%s: %s: invalid _PCT length\n", DEVNAME(sc), | |||
875 | sc->sc_devnode->name); | |||
876 | return (1); | |||
877 | } | |||
878 | ||||
879 | memcpy(&sc->sc_pct.pct_ctrl, res.v_package[0]->v_buffer,__builtin_memcpy((&sc->sc_pct.pct_ctrl), (res._.vpackage [0]->_.vbuffer), (sizeof sc->sc_pct.pct_ctrl)) | |||
880 | sizeof sc->sc_pct.pct_ctrl)__builtin_memcpy((&sc->sc_pct.pct_ctrl), (res._.vpackage [0]->_.vbuffer), (sizeof sc->sc_pct.pct_ctrl)); | |||
881 | if (sc->sc_pct.pct_ctrl.grd_gas.address_space_id == | |||
882 | GAS_FUNCTIONAL_FIXED127) { | |||
883 | dnprintf(20, "CTRL GASIO is functional fixed hardware.\n"); | |||
884 | goto ffh; | |||
885 | } | |||
886 | ||||
887 | memcpy(&sc->sc_pct.pct_status, res.v_package[1]->v_buffer,__builtin_memcpy((&sc->sc_pct.pct_status), (res._.vpackage [1]->_.vbuffer), (sizeof sc->sc_pct.pct_status)) | |||
888 | sizeof sc->sc_pct.pct_status)__builtin_memcpy((&sc->sc_pct.pct_status), (res._.vpackage [1]->_.vbuffer), (sizeof sc->sc_pct.pct_status)); | |||
889 | if (sc->sc_pct.pct_status.grd_gas.address_space_id == | |||
890 | GAS_FUNCTIONAL_FIXED127) { | |||
891 | dnprintf(20, "CTRL GASIO is functional fixed hardware.\n"); | |||
892 | goto ffh; | |||
893 | } | |||
894 | ||||
895 | dnprintf(10, "_PCT(ctrl) : %02x %04x %02x %02x %02x %02x %016llx\n", | |||
896 | sc->sc_pct.pct_ctrl.grd_descriptor, | |||
897 | sc->sc_pct.pct_ctrl.grd_length, | |||
898 | sc->sc_pct.pct_ctrl.grd_gas.address_space_id, | |||
899 | sc->sc_pct.pct_ctrl.grd_gas.register_bit_width, | |||
900 | sc->sc_pct.pct_ctrl.grd_gas.register_bit_offset, | |||
901 | sc->sc_pct.pct_ctrl.grd_gas.access_size, | |||
902 | sc->sc_pct.pct_ctrl.grd_gas.address); | |||
903 | ||||
904 | dnprintf(10, "_PCT(status): %02x %04x %02x %02x %02x %02x %016llx\n", | |||
905 | sc->sc_pct.pct_status.grd_descriptor, | |||
906 | sc->sc_pct.pct_status.grd_length, | |||
907 | sc->sc_pct.pct_status.grd_gas.address_space_id, | |||
908 | sc->sc_pct.pct_status.grd_gas.register_bit_width, | |||
909 | sc->sc_pct.pct_status.grd_gas.register_bit_offset, | |||
910 | sc->sc_pct.pct_status.grd_gas.access_size, | |||
911 | sc->sc_pct.pct_status.grd_gas.address); | |||
912 | ||||
913 | /* if not set assume single 32 bit access */ | |||
914 | sc->sc_pct_stat_as = sc->sc_pct.pct_status.grd_gas.register_bit_width | |||
915 | / 8; | |||
916 | if (sc->sc_pct_stat_as == 0) | |||
917 | sc->sc_pct_stat_as = 4; | |||
918 | sc->sc_pct_ctrl_as = sc->sc_pct.pct_ctrl.grd_gas.register_bit_width / 8; | |||
919 | if (sc->sc_pct_ctrl_as == 0) | |||
920 | sc->sc_pct_ctrl_as = 4; | |||
921 | sc->sc_pct_stat_len = sc->sc_pct.pct_status.grd_gas.access_size; | |||
922 | if (sc->sc_pct_stat_len == 0) | |||
923 | sc->sc_pct_stat_len = sc->sc_pct_stat_as; | |||
924 | sc->sc_pct_ctrl_len = sc->sc_pct.pct_ctrl.grd_gas.access_size; | |||
925 | if (sc->sc_pct_ctrl_len == 0) | |||
926 | sc->sc_pct_ctrl_len = sc->sc_pct_ctrl_as; | |||
927 | ||||
928 | rv = 0; | |||
929 | ffh: | |||
930 | aml_freevalue(&res); | |||
931 | return (rv); | |||
932 | } | |||
933 | ||||
934 | int | |||
935 | acpicpu_getpss(struct acpicpu_softc *sc) | |||
936 | { | |||
937 | struct aml_value res; | |||
938 | int i, c, cf; | |||
939 | ||||
940 | if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSS", 0, NULL((void *)0), &res)) { | |||
941 | dprintf("%s: no _PSS\n", DEVNAME(sc)); | |||
942 | return (1); | |||
943 | } | |||
944 | ||||
945 | free(sc->sc_pss, M_DEVBUF2, sc->sc_pssfulllen); | |||
946 | ||||
947 | sc->sc_pss = mallocarray(res.length, sizeof(*sc->sc_pss), M_DEVBUF2, | |||
948 | M_WAITOK0x0001 | M_ZERO0x0008); | |||
949 | sc->sc_pssfulllen = res.length * sizeof(*sc->sc_pss); | |||
950 | ||||
951 | c = 0; | |||
952 | for (i = 0; i < res.length; i++) { | |||
953 | cf = aml_val2int(res.v_package_.vpackage[i]->v_package_.vpackage[0]); | |||
954 | ||||
955 | /* This heuristic comes from FreeBSDs | |||
956 | * dev/acpica/acpi_perf.c to weed out invalid PSS entries. | |||
957 | */ | |||
958 | if (cf == sc->sc_pss[c].pss_core_freq) { | |||
959 | printf("%s: struck PSS entry, core frequency equals " | |||
960 | " last\n", sc->sc_dev.dv_xname); | |||
961 | continue; | |||
962 | } | |||
963 | ||||
964 | if (cf == 0xFFFF || cf == 0x9999 || cf == 99999 || cf == 0) { | |||
965 | printf("%s: struck PSS entry, inappropriate core " | |||
966 | "frequency value\n", sc->sc_dev.dv_xname); | |||
967 | continue; | |||
968 | } | |||
969 | ||||
970 | sc->sc_pss[c].pss_core_freq = cf; | |||
971 | sc->sc_pss[c].pss_power = aml_val2int( | |||
972 | res.v_package_.vpackage[i]->v_package_.vpackage[1]); | |||
973 | sc->sc_pss[c].pss_trans_latency = aml_val2int( | |||
974 | res.v_package_.vpackage[i]->v_package_.vpackage[2]); | |||
975 | sc->sc_pss[c].pss_bus_latency = aml_val2int( | |||
976 | res.v_package_.vpackage[i]->v_package_.vpackage[3]); | |||
977 | sc->sc_pss[c].pss_ctrl = aml_val2int( | |||
978 | res.v_package_.vpackage[i]->v_package_.vpackage[4]); | |||
979 | sc->sc_pss[c].pss_status = aml_val2int( | |||
980 | res.v_package_.vpackage[i]->v_package_.vpackage[5]); | |||
981 | c++; | |||
982 | } | |||
983 | sc->sc_pss_len = c; | |||
984 | ||||
985 | aml_freevalue(&res); | |||
986 | ||||
987 | return (0); | |||
988 | } | |||
989 | ||||
990 | int | |||
991 | acpicpu_fetch_pss(struct acpicpu_pss **pss) | |||
992 | { | |||
993 | struct acpicpu_softc *sc; | |||
994 | ||||
995 | /* | |||
996 | * XXX: According to the ACPI spec in an SMP system all processors | |||
997 | * are supposed to support the same states. For now we pray | |||
998 | * the bios ensures this... | |||
999 | */ | |||
1000 | ||||
1001 | sc = (struct acpicpu_softc *)cpu_info_primary(*(struct cpu_info *)((char *)&cpu_info_full_primary + 4096 *2 - __builtin_offsetof(struct cpu_info, ci_dev))).ci_acpicpudev; | |||
1002 | if (!sc) | |||
1003 | return 0; | |||
1004 | *pss = sc->sc_pss; | |||
1005 | ||||
1006 | return (sc->sc_pss_len); | |||
1007 | } | |||
1008 | ||||
1009 | int | |||
1010 | acpicpu_notify(struct aml_node *node, int notify_type, void *arg) | |||
1011 | { | |||
1012 | struct acpicpu_softc *sc = arg; | |||
1013 | ||||
1014 | dnprintf(10, "acpicpu_notify: %.2x %s\n", notify_type, | |||
1015 | sc->sc_devnode->name); | |||
1016 | ||||
1017 | switch (notify_type) { | |||
1018 | case 0x80: /* _PPC changed, retrieve new values */ | |||
1019 | acpicpu_getppc(sc); | |||
1020 | acpicpu_getpss(sc); | |||
1021 | if (sc->sc_notify) | |||
1022 | sc->sc_notify(sc->sc_pss, sc->sc_pss_len); | |||
1023 | break; | |||
1024 | ||||
1025 | case 0x81: /* _CST changed, retrieve new values */ | |||
1026 | acpicpu_getcst(sc); | |||
1027 | printf("%s: notify", DEVNAME(sc)((sc)->sc_dev.dv_xname)); | |||
1028 | acpicpu_print_cst(sc); | |||
1029 | printf("\n"); | |||
1030 | break; | |||
1031 | ||||
1032 | default: | |||
1033 | printf("%s: unhandled cpu event %x\n", DEVNAME(sc)((sc)->sc_dev.dv_xname), | |||
1034 | notify_type); | |||
1035 | break; | |||
1036 | } | |||
1037 | ||||
1038 | return (0); | |||
1039 | } | |||
1040 | ||||
1041 | void | |||
1042 | acpicpu_set_notify(void (*func)(struct acpicpu_pss *, int)) | |||
1043 | { | |||
1044 | struct acpicpu_softc *sc; | |||
1045 | ||||
1046 | sc = (struct acpicpu_softc *)cpu_info_primary(*(struct cpu_info *)((char *)&cpu_info_full_primary + 4096 *2 - __builtin_offsetof(struct cpu_info, ci_dev))).ci_acpicpudev; | |||
1047 | if (sc != NULL((void *)0)) | |||
1048 | sc->sc_notify = func; | |||
1049 | } | |||
1050 | ||||
1051 | void | |||
1052 | acpicpu_setperf_ppc_change(struct acpicpu_pss *pss, int npss) | |||
1053 | { | |||
1054 | struct acpicpu_softc *sc; | |||
1055 | ||||
1056 | sc = (struct acpicpu_softc *)cpu_info_primary(*(struct cpu_info *)((char *)&cpu_info_full_primary + 4096 *2 - __builtin_offsetof(struct cpu_info, ci_dev))).ci_acpicpudev; | |||
1057 | ||||
1058 | if (sc != NULL((void *)0)) | |||
1059 | cpu_setperf(sc->sc_level); | |||
1060 | } | |||
1061 | ||||
1062 | void | |||
1063 | acpicpu_setperf(int level) | |||
1064 | { | |||
1065 | struct acpicpu_softc *sc; | |||
1066 | struct acpicpu_pss *pss = NULL((void *)0); | |||
1067 | int idx, len; | |||
1068 | uint32_t status = 0; | |||
1069 | ||||
1070 | sc = (struct acpicpu_softc *)curcpu()({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;})->ci_acpicpudev; | |||
1071 | ||||
1072 | dnprintf(10, "%s: acpicpu setperf level %d\n", | |||
1073 | sc->sc_devnode->name, level); | |||
1074 | ||||
1075 | if (level < 0 || level > 100) { | |||
1076 | dnprintf(10, "%s: acpicpu setperf illegal percentage\n", | |||
1077 | sc->sc_devnode->name); | |||
1078 | return; | |||
1079 | } | |||
1080 | ||||
1081 | /* | |||
1082 | * XXX this should be handled more gracefully and it needs to also do | |||
1083 | * the duty cycle method instead of pss exclusively | |||
1084 | */ | |||
1085 | if (sc->sc_flags & FLAGS_NOPSS0x10 || sc->sc_flags & FLAGS_NOPCT0x20) { | |||
1086 | dnprintf(10, "%s: acpicpu no _PSS or _PCT\n", | |||
1087 | sc->sc_devnode->name); | |||
1088 | return; | |||
1089 | } | |||
1090 | ||||
1091 | if (sc->sc_ppc) | |||
1092 | len = sc->sc_ppc; | |||
1093 | else | |||
1094 | len = sc->sc_pss_len; | |||
1095 | idx = (len - 1) - (level / (100 / len)); | |||
1096 | if (idx < 0) | |||
1097 | idx = 0; | |||
1098 | ||||
1099 | if (sc->sc_ppc) | |||
1100 | idx += sc->sc_pss_len - sc->sc_ppc; | |||
1101 | ||||
1102 | if (idx > sc->sc_pss_len) | |||
1103 | idx = sc->sc_pss_len - 1; | |||
1104 | ||||
1105 | dnprintf(10, "%s: acpicpu setperf index %d pss_len %d ppc %d\n", | |||
1106 | sc->sc_devnode->name, idx, sc->sc_pss_len, sc->sc_ppc); | |||
1107 | ||||
1108 | pss = &sc->sc_pss[idx]; | |||
1109 | ||||
1110 | #ifdef ACPI_DEBUG | |||
1111 | /* keep this for now since we will need this for debug in the field */ | |||
1112 | printf("0 status: %x %llx %u %u ctrl: %x %llx %u %u\n", | |||
1113 | sc->sc_pct.pct_status.grd_gas.address_space_id, | |||
1114 | sc->sc_pct.pct_status.grd_gas.address, | |||
1115 | sc->sc_pct_stat_as, sc->sc_pct_stat_len, | |||
1116 | sc->sc_pct.pct_ctrl.grd_gas.address_space_id, | |||
1117 | sc->sc_pct.pct_ctrl.grd_gas.address, | |||
1118 | sc->sc_pct_ctrl_as, sc->sc_pct_ctrl_len); | |||
1119 | #endif | |||
1120 | acpi_gasio(sc->sc_acpi, ACPI_IOREAD0, | |||
1121 | sc->sc_pct.pct_status.grd_gas.address_space_id, | |||
1122 | sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as, | |||
1123 | sc->sc_pct_stat_len, &status); | |||
1124 | dnprintf(20, "1 status: %u <- %u\n", status, pss->pss_status); | |||
1125 | ||||
1126 | /* Are we already at the requested frequency? */ | |||
1127 | if (status == pss->pss_status) | |||
1128 | return; | |||
1129 | ||||
1130 | acpi_gasio(sc->sc_acpi, ACPI_IOWRITE1, | |||
1131 | sc->sc_pct.pct_ctrl.grd_gas.address_space_id, | |||
1132 | sc->sc_pct.pct_ctrl.grd_gas.address, sc->sc_pct_ctrl_as, | |||
1133 | sc->sc_pct_ctrl_len, &pss->pss_ctrl); | |||
1134 | dnprintf(20, "pss_ctrl: %x\n", pss->pss_ctrl); | |||
1135 | ||||
1136 | acpi_gasio(sc->sc_acpi, ACPI_IOREAD0, | |||
1137 | sc->sc_pct.pct_status.grd_gas.address_space_id, | |||
1138 | sc->sc_pct.pct_status.grd_gas.address, sc->sc_pct_stat_as, | |||
1139 | sc->sc_pct_stat_as, &status); | |||
1140 | dnprintf(20, "2 status: %d\n", status); | |||
1141 | ||||
1142 | /* Did the transition succeed? */ | |||
1143 | if (status == pss->pss_status) { | |||
1144 | cpuspeed = pss->pss_core_freq; | |||
1145 | sc->sc_level = level; | |||
1146 | } else | |||
1147 | printf("%s: acpicpu setperf failed to alter frequency\n", | |||
1148 | sc->sc_devnode->name); | |||
1149 | } | |||
1150 | ||||
1151 | void | |||
1152 | acpicpu_idle(void) | |||
1153 | { | |||
1154 | struct cpu_info *ci = curcpu()({struct cpu_info *__ci; asm volatile("movq %%gs:%P1,%0" : "=r" (__ci) :"n" (__builtin_offsetof(struct cpu_info, ci_self))); __ci;}); | |||
1155 | struct acpicpu_softc *sc = (struct acpicpu_softc *)ci->ci_acpicpudev; | |||
1156 | struct acpi_cstate *best, *cx; | |||
1157 | unsigned long itime; | |||
1158 | ||||
1159 | if (sc == NULL((void *)0)) { | |||
| ||||
1160 | __asm volatile("sti"); | |||
1161 | panic("null acpicpu"); | |||
1162 | } | |||
1163 | ||||
1164 | /* possibly update the MWAIT_ONLY flag in cpu_info */ | |||
1165 | if (sc->sc_flags & FLAGS_MWAIT_ONLY0x02) { | |||
1166 | if ((ci->ci_mwait & MWAIT_ONLY0x4) == 0) | |||
1167 | atomic_setbits_intx86_atomic_setbits_u32(&ci->ci_mwait, MWAIT_ONLY0x4); | |||
1168 | } else if (ci->ci_mwait & MWAIT_ONLY0x4) | |||
1169 | atomic_clearbits_intx86_atomic_clearbits_u32(&ci->ci_mwait, MWAIT_ONLY0x4); | |||
1170 | ||||
1171 | /* | |||
1172 | * Find the first state with a latency we'll accept, ignoring | |||
1173 | * states marked skippable | |||
1174 | */ | |||
1175 | best = cx = SLIST_FIRST(&sc->sc_cstates)((&sc->sc_cstates)->slh_first); | |||
1176 | while ((cx->flags & CST_FLAG_SKIP0x8000) || | |||
1177 | cx->latency * 3 > sc->sc_prev_sleep) { | |||
1178 | if ((cx = SLIST_NEXT(cx, link)((cx)->link.sle_next)) == NULL((void *)0)) | |||
1179 | break; | |||
1180 | best = cx; | |||
1181 | } | |||
1182 | ||||
1183 | if (best->state >= 3 && | |||
1184 | (best->flags & CST_FLAG_MWAIT_BM_AVOIDANCE0x2) && | |||
1185 | acpi_read_pmreg(acpi_softc, ACPIREG_PM1_STS0x0E, 0) & ACPI_PM1_BM_STS0x0010) { | |||
1186 | /* clear it and back off */ | |||
1187 | acpi_write_pmreg(acpi_softc, ACPIREG_PM1_STS0x0E, 0, | |||
1188 | ACPI_PM1_BM_STS0x0010); | |||
1189 | while ((cx = SLIST_NEXT(cx, link)((cx)->link.sle_next)) != NULL((void *)0)) { | |||
1190 | if (cx->flags & CST_FLAG_SKIP0x8000) | |||
1191 | continue; | |||
1192 | if (cx->state < 3 || | |||
1193 | (cx->flags & CST_FLAG_MWAIT_BM_AVOIDANCE0x2) == 0) | |||
1194 | break; | |||
1195 | } | |||
1196 | best = cx; | |||
1197 | } | |||
1198 | ||||
1199 | ||||
1200 | atomic_inc_long(&cst_stats[best->state])_atomic_inc_long(&cst_stats[best->state]); | |||
| ||||
1201 | ||||
1202 | itime = tick / 2; | |||
1203 | switch (best->method) { | |||
1204 | default: | |||
1205 | case CST_METH_HALT0: | |||
1206 | __asm volatile("sti; hlt"); | |||
1207 | break; | |||
1208 | ||||
1209 | case CST_METH_IO_HALT1: | |||
1210 | inb((u_short)best->address)( (__builtin_constant_p(((u_short)best->address)) && ((u_short)best->address) < 0x100) ? __inbc((u_short)best ->address) : __inb((u_short)best->address)); | |||
1211 | __asm volatile("sti; hlt"); | |||
1212 | break; | |||
1213 | ||||
1214 | case CST_METH_MWAIT2: | |||
1215 | { | |||
1216 | struct timeval start, stop; | |||
1217 | unsigned int hints; | |||
1218 | ||||
1219 | #ifdef __LP64__1 | |||
1220 | if ((read_rflags() & PSL_I0x00000200) == 0) | |||
1221 | panic("idle with interrupts blocked!"); | |||
1222 | #else | |||
1223 | if ((read_eflags() & PSL_I0x00000200) == 0) | |||
1224 | panic("idle with interrupts blocked!"); | |||
1225 | #endif | |||
1226 | ||||
1227 | /* something already queued? */ | |||
1228 | if (!cpu_is_idle(ci)((ci)->ci_schedstate.spc_whichqs == 0)) | |||
1229 | return; | |||
1230 | ||||
1231 | /* | |||
1232 | * About to idle; setting the MWAIT_IN_IDLE bit tells | |||
1233 | * cpu_unidle() that it can't be a no-op and tells cpu_kick() | |||
1234 | * that it doesn't need to use an IPI. We also set the | |||
1235 | * MWAIT_KEEP_IDLING bit: those routines clear it to stop | |||
1236 | * the mwait. Once they're set, we do a final check of the | |||
1237 | * queue, in case another cpu called setrunqueue() and added | |||
1238 | * something to the queue and called cpu_unidle() between | |||
1239 | * the check in sched_idle() and here. | |||
1240 | */ | |||
1241 | hints = (unsigned)best->address; | |||
1242 | microuptime(&start); | |||
1243 | atomic_setbits_intx86_atomic_setbits_u32(&ci->ci_mwait, MWAIT_IDLING(0x1 | 0x2)); | |||
1244 | if (cpu_is_idle(ci)((ci)->ci_schedstate.spc_whichqs == 0)) { | |||
1245 | /* intel errata AAI65: cflush before monitor */ | |||
1246 | if (ci->ci_cflushsz != 0 && | |||
1247 | strcmp(cpu_vendor, "GenuineIntel") == 0) { | |||
1248 | membar_sync()do { __asm volatile("mfence" ::: "memory"); } while (0); | |||
1249 | clflush((unsigned long)&ci->ci_mwait); | |||
1250 | membar_sync()do { __asm volatile("mfence" ::: "memory"); } while (0); | |||
1251 | } | |||
1252 | ||||
1253 | monitor(&ci->ci_mwait, 0, 0); | |||
1254 | if ((ci->ci_mwait & MWAIT_IDLING(0x1 | 0x2)) == MWAIT_IDLING(0x1 | 0x2)) | |||
1255 | mwait(0, hints); | |||
1256 | } | |||
1257 | ||||
1258 | microuptime(&stop); | |||
1259 | timersub(&stop, &start, &stop)do { (&stop)->tv_sec = (&stop)->tv_sec - (& start)->tv_sec; (&stop)->tv_usec = (&stop)-> tv_usec - (&start)->tv_usec; if ((&stop)->tv_usec < 0) { (&stop)->tv_sec--; (&stop)->tv_usec += 1000000; } } while (0); | |||
1260 | itime = stop.tv_sec * 1000000 + stop.tv_usec; | |||
1261 | ||||
1262 | /* done idling; let cpu_kick() know that an IPI is required */ | |||
1263 | atomic_clearbits_intx86_atomic_clearbits_u32(&ci->ci_mwait, MWAIT_IDLING(0x1 | 0x2)); | |||
1264 | break; | |||
1265 | } | |||
1266 | ||||
1267 | case CST_METH_GAS_IO3: | |||
1268 | inb((u_short)best->address)( (__builtin_constant_p(((u_short)best->address)) && ((u_short)best->address) < 0x100) ? __inbc((u_short)best ->address) : __inb((u_short)best->address)); | |||
1269 | /* something harmless to give system time to change state */ | |||
1270 | acpi_read_pmreg(acpi_softc, ACPIREG_PM1_STS0x0E, 0); | |||
1271 | break; | |||
1272 | ||||
1273 | } | |||
1274 | ||||
1275 | sc->sc_last_itime = itime; | |||
1276 | itime >>= 1; | |||
1277 | sc->sc_prev_sleep = (sc->sc_prev_sleep + (sc->sc_prev_sleep >> 1) | |||
1278 | + itime) >> 1; | |||
1279 | } |