| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: acpi_ec.c,v 1.86 2021/12/31 17:22:25 riastradh Exp $ */ | | 1 | /* $NetBSD: acpi_ec.c,v 1.86.4.1 2023/07/30 12:01:53 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>. | | 4 | * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * | | 10 | * |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in | | 14 | * notice, this list of conditions and the following disclaimer in |
| @@ -24,52 +24,54 @@ | | | @@ -24,52 +24,54 @@ |
24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 24 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 25 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 26 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | | 27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
28 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 28 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * The ACPI Embedded Controller (EC) driver serves two different purposes: | | 33 | * The ACPI Embedded Controller (EC) driver serves two different purposes: |
34 | * - read and write access from ASL, e.g. to read battery state | | 34 | * - read and write access from ASL, e.g. to read battery state |
35 | * - notification of ASL of System Control Interrupts. | | 35 | * - notification of ASL of System Control Interrupts. |
36 | * | | 36 | * |
37 | * Access to the EC is serialised by sc_access_mtx and optionally the | | 37 | * Lock order: |
38 | * ACPI global mutex. Both locks are held until the request is fulfilled. | | 38 | * sc_access_mtx (serializes EC transactions -- read, write, or SCI) |
39 | * All access to the softc has to hold sc_mtx to serialise against the GPE | | 39 | * -> ACPI global lock (excludes other ACPI access during EC transaction) |
40 | * handler and the callout. sc_mtx is also used for wakeup conditions. | | 40 | * -> sc_mtx (serializes state machine transitions and waits) |
41 | * | | 41 | * |
42 | * SCIs are processed in a kernel thread. Handling gets a bit complicated | | 42 | * SCIs are processed in a kernel thread. |
43 | * by the lock order (sc_mtx must be acquired after sc_access_mtx and the | | | |
44 | * ACPI global mutex). | | | |
45 | * | | 43 | * |
46 | * Read and write requests spin around for a short time as many requests | | 44 | * Read and write requests spin around for a short time as many requests |
47 | * can be handled instantly by the EC. During normal processing interrupt | | 45 | * can be handled instantly by the EC. During normal processing interrupt |
48 | * mode is used exclusively. At boot and resume time interrupts are not | | 46 | * mode is used exclusively. At boot and resume time interrupts are not |
49 | * working and the handlers just busy loop. | | 47 | * working and the handlers just busy loop. |
50 | * | | 48 | * |
51 | * A callout is scheduled to compensate for missing interrupts on some | | 49 | * A callout is scheduled to compensate for missing interrupts on some |
52 | * hardware. If the EC doesn't process a request for 5s, it is most likely | | 50 | * hardware. If the EC doesn't process a request for 5s, it is most likely |
53 | * in a wedged state. No method to reset the EC is currently known. | | 51 | * in a wedged state. No method to reset the EC is currently known. |
54 | * | | 52 | * |
55 | * Special care has to be taken to not poll the EC in a busy loop without | | 53 | * Special care has to be taken to not poll the EC in a busy loop without |
56 | * delay. This can prevent processing of Power Button events. At least some | | 54 | * delay. This can prevent processing of Power Button events. At least some |
57 | * Lenovo Thinkpads seem to be implement the Power Button Override in the EC | | 55 | * Lenovo Thinkpads seem to be implement the Power Button Override in the EC |
58 | * and the only option to recover on those models is to cut off all power. | | 56 | * and the only option to recover on those models is to cut off all power. |
59 | */ | | 57 | */ |
60 | | | 58 | |
61 | #include <sys/cdefs.h> | | 59 | #include <sys/cdefs.h> |
62 | __KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.86 2021/12/31 17:22:25 riastradh Exp $"); | | 60 | __KERNEL_RCSID(0, "$NetBSD: acpi_ec.c,v 1.86.4.1 2023/07/30 12:01:53 martin Exp $"); |
| | | 61 | |
| | | 62 | #ifdef _KERNEL_OPT |
| | | 63 | #include "opt_acpi_ec.h" |
| | | 64 | #endif |
63 | | | 65 | |
64 | #include <sys/param.h> | | 66 | #include <sys/param.h> |
65 | #include <sys/callout.h> | | 67 | #include <sys/callout.h> |
66 | #include <sys/condvar.h> | | 68 | #include <sys/condvar.h> |
67 | #include <sys/device.h> | | 69 | #include <sys/device.h> |
68 | #include <sys/kernel.h> | | 70 | #include <sys/kernel.h> |
69 | #include <sys/kthread.h> | | 71 | #include <sys/kthread.h> |
70 | #include <sys/mutex.h> | | 72 | #include <sys/mutex.h> |
71 | #include <sys/systm.h> | | 73 | #include <sys/systm.h> |
72 | | | 74 | |
73 | #include <dev/acpi/acpireg.h> | | 75 | #include <dev/acpi/acpireg.h> |
74 | #include <dev/acpi/acpivar.h> | | 76 | #include <dev/acpi/acpivar.h> |
75 | #include <dev/acpi/acpi_ecvar.h> | | 77 | #include <dev/acpi/acpi_ecvar.h> |
| @@ -91,92 +93,159 @@ ACPI_MODULE_NAME ("acpi_ec") | | | @@ -91,92 +93,159 @@ ACPI_MODULE_NAME ("acpi_ec") |
91 | #define EC_COMMAND_WRITE 0x81 | | 93 | #define EC_COMMAND_WRITE 0x81 |
92 | #define EC_COMMAND_BURST_EN 0x82 | | 94 | #define EC_COMMAND_BURST_EN 0x82 |
93 | #define EC_COMMAND_BURST_DIS 0x83 | | 95 | #define EC_COMMAND_BURST_DIS 0x83 |
94 | #define EC_COMMAND_QUERY 0x84 | | 96 | #define EC_COMMAND_QUERY 0x84 |
95 | | | 97 | |
96 | /* From ACPI 3.0b, chapter 12.2.1 */ | | 98 | /* From ACPI 3.0b, chapter 12.2.1 */ |
97 | #define EC_STATUS_OBF 0x01 | | 99 | #define EC_STATUS_OBF 0x01 |
98 | #define EC_STATUS_IBF 0x02 | | 100 | #define EC_STATUS_IBF 0x02 |
99 | #define EC_STATUS_CMD 0x08 | | 101 | #define EC_STATUS_CMD 0x08 |
100 | #define EC_STATUS_BURST 0x10 | | 102 | #define EC_STATUS_BURST 0x10 |
101 | #define EC_STATUS_SCI 0x20 | | 103 | #define EC_STATUS_SCI 0x20 |
102 | #define EC_STATUS_SMI 0x40 | | 104 | #define EC_STATUS_SMI 0x40 |
103 | | | 105 | |
| | | 106 | #define EC_STATUS_FMT \ |
| | | 107 | "\x10\10IGN7\7SMI\6SCI\5BURST\4CMD\3IGN2\2IBF\1OBF" |
| | | 108 | |
104 | static const struct device_compatible_entry compat_data[] = { | | 109 | static const struct device_compatible_entry compat_data[] = { |
105 | { .compat = "PNP0C09" }, | | 110 | { .compat = "PNP0C09" }, |
106 | DEVICE_COMPAT_EOL | | 111 | DEVICE_COMPAT_EOL |
107 | }; | | 112 | }; |
108 | | | 113 | |
| | | 114 | #define EC_STATE_ENUM(F) \ |
| | | 115 | F(EC_STATE_QUERY, "QUERY") \ |
| | | 116 | F(EC_STATE_QUERY_VAL, "QUERY_VAL") \ |
| | | 117 | F(EC_STATE_READ, "READ") \ |
| | | 118 | F(EC_STATE_READ_ADDR, "READ_ADDR") \ |
| | | 119 | F(EC_STATE_READ_VAL, "READ_VAL") \ |
| | | 120 | F(EC_STATE_WRITE, "WRITE") \ |
| | | 121 | F(EC_STATE_WRITE_ADDR, "WRITE_ADDR") \ |
| | | 122 | F(EC_STATE_WRITE_VAL, "WRITE_VAL") \ |
| | | 123 | F(EC_STATE_FREE, "FREE") \ |
| | | 124 | |
109 | enum ec_state_t { | | 125 | enum ec_state_t { |
110 | EC_STATE_QUERY, | | 126 | #define F(N, S) N, |
111 | EC_STATE_QUERY_VAL, | | 127 | EC_STATE_ENUM(F) |
112 | EC_STATE_READ, | | 128 | #undef F |
113 | EC_STATE_READ_ADDR, | | 129 | }; |
114 | EC_STATE_READ_VAL, | | 130 | |
115 | EC_STATE_WRITE, | | 131 | #ifdef ACPIEC_DEBUG |
116 | EC_STATE_WRITE_ADDR, | | 132 | static const char *const acpiec_state_names[] = { |
117 | EC_STATE_WRITE_VAL, | | 133 | #define F(N, S) [N] = S, |
118 | EC_STATE_FREE | | 134 | EC_STATE_ENUM(F) |
| | | 135 | #undef F |
119 | }; | | 136 | }; |
| | | 137 | #endif |
120 | | | 138 | |
121 | struct acpiec_softc { | | 139 | struct acpiec_softc { |
| | | 140 | device_t sc_dev; |
| | | 141 | |
122 | ACPI_HANDLE sc_ech; | | 142 | ACPI_HANDLE sc_ech; |
123 | | | 143 | |
124 | ACPI_HANDLE sc_gpeh; | | 144 | ACPI_HANDLE sc_gpeh; |
125 | uint8_t sc_gpebit; | | 145 | uint8_t sc_gpebit; |
126 | | | 146 | |
127 | bus_space_tag_t sc_data_st; | | 147 | bus_space_tag_t sc_data_st; |
128 | bus_space_handle_t sc_data_sh; | | 148 | bus_space_handle_t sc_data_sh; |
129 | | | 149 | |
130 | bus_space_tag_t sc_csr_st; | | 150 | bus_space_tag_t sc_csr_st; |
131 | bus_space_handle_t sc_csr_sh; | | 151 | bus_space_handle_t sc_csr_sh; |
132 | | | 152 | |
133 | bool sc_need_global_lock; | | 153 | bool sc_need_global_lock; |
134 | uint32_t sc_global_lock; | | 154 | uint32_t sc_global_lock; |
135 | | | 155 | |
136 | kmutex_t sc_mtx, sc_access_mtx; | | 156 | kmutex_t sc_mtx, sc_access_mtx; |
137 | kcondvar_t sc_cv, sc_cv_sci; | | 157 | kcondvar_t sc_cv, sc_cv_sci; |
138 | enum ec_state_t sc_state; | | 158 | enum ec_state_t sc_state; |
139 | bool sc_got_sci; | | 159 | bool sc_got_sci; |
140 | callout_t sc_pseudo_intr; | | 160 | callout_t sc_pseudo_intr; |
141 | | | 161 | |
142 | uint8_t sc_cur_addr, sc_cur_val; | | 162 | uint8_t sc_cur_addr, sc_cur_val; |
143 | }; | | 163 | }; |
144 | | | 164 | |
| | | 165 | #ifdef ACPIEC_DEBUG |
| | | 166 | |
| | | 167 | #define ACPIEC_DEBUG_ENUM(F) \ |
| | | 168 | F(ACPIEC_DEBUG_REG, "REG") \ |
| | | 169 | F(ACPIEC_DEBUG_RW, "RW") \ |
| | | 170 | F(ACPIEC_DEBUG_QUERY, "QUERY") \ |
| | | 171 | F(ACPIEC_DEBUG_TRANSITION, "TRANSITION") \ |
| | | 172 | F(ACPIEC_DEBUG_INTR, "INTR") \ |
| | | 173 | |
| | | 174 | enum { |
| | | 175 | #define F(N, S) N, |
| | | 176 | ACPIEC_DEBUG_ENUM(F) |
| | | 177 | #undef F |
| | | 178 | }; |
| | | 179 | |
| | | 180 | static const char *const acpiec_debug_names[] = { |
| | | 181 | #define F(N, S) [N] = S, |
| | | 182 | ACPIEC_DEBUG_ENUM(F) |
| | | 183 | #undef F |
| | | 184 | }; |
| | | 185 | |
| | | 186 | int acpiec_debug = ACPIEC_DEBUG; |
| | | 187 | |
| | | 188 | #define DPRINTF(n, sc, fmt, ...) do \ |
| | | 189 | { \ |
| | | 190 | if (acpiec_debug & __BIT(n)) { \ |
| | | 191 | char dprintbuf[16]; \ |
| | | 192 | const char *state; \ |
| | | 193 | \ |
| | | 194 | /* paranoia */ \ |
| | | 195 | if ((sc)->sc_state < __arraycount(acpiec_state_names)) { \ |
| | | 196 | state = acpiec_state_names[(sc)->sc_state]; \ |
| | | 197 | } else { \ |
| | | 198 | snprintf(dprintbuf, sizeof(dprintbuf), "0x%x", \ |
| | | 199 | (sc)->sc_state); \ |
| | | 200 | state = dprintbuf; \ |
| | | 201 | } \ |
| | | 202 | \ |
| | | 203 | device_printf((sc)->sc_dev, "(%s) [%s] "fmt, \ |
| | | 204 | acpiec_debug_names[n], state, ##__VA_ARGS__); \ |
| | | 205 | } \ |
| | | 206 | } while (0) |
| | | 207 | |
| | | 208 | #else |
| | | 209 | |
| | | 210 | #define DPRINTF(n, sc, fmt, ...) __nothing |
| | | 211 | |
| | | 212 | #endif |
| | | 213 | |
145 | static int acpiecdt_match(device_t, cfdata_t, void *); | | 214 | static int acpiecdt_match(device_t, cfdata_t, void *); |
146 | static void acpiecdt_attach(device_t, device_t, void *); | | 215 | static void acpiecdt_attach(device_t, device_t, void *); |
147 | | | 216 | |
148 | static int acpiec_match(device_t, cfdata_t, void *); | | 217 | static int acpiec_match(device_t, cfdata_t, void *); |
149 | static void acpiec_attach(device_t, device_t, void *); | | 218 | static void acpiec_attach(device_t, device_t, void *); |
150 | | | 219 | |
151 | static void acpiec_common_attach(device_t, device_t, ACPI_HANDLE, | | 220 | static void acpiec_common_attach(device_t, device_t, ACPI_HANDLE, |
152 | bus_space_tag_t, bus_addr_t, bus_space_tag_t, bus_addr_t, | | 221 | bus_space_tag_t, bus_addr_t, bus_space_tag_t, bus_addr_t, |
153 | ACPI_HANDLE, uint8_t); | | 222 | ACPI_HANDLE, uint8_t); |
154 | | | 223 | |
155 | static bool acpiec_suspend(device_t, const pmf_qual_t *); | | 224 | static bool acpiec_suspend(device_t, const pmf_qual_t *); |
156 | static bool acpiec_resume(device_t, const pmf_qual_t *); | | 225 | static bool acpiec_resume(device_t, const pmf_qual_t *); |
157 | static bool acpiec_shutdown(device_t, int); | | 226 | static bool acpiec_shutdown(device_t, int); |
158 | | | 227 | |
159 | static bool acpiec_parse_gpe_package(device_t, ACPI_HANDLE, | | 228 | static bool acpiec_parse_gpe_package(device_t, ACPI_HANDLE, |
160 | ACPI_HANDLE *, uint8_t *); | | 229 | ACPI_HANDLE *, uint8_t *); |
161 | | | 230 | |
162 | static void acpiec_callout(void *); | | 231 | static void acpiec_callout(void *); |
163 | static void acpiec_gpe_query(void *); | | 232 | static void acpiec_gpe_query(void *); |
164 | static uint32_t acpiec_gpe_handler(ACPI_HANDLE, uint32_t, void *); | | 233 | static uint32_t acpiec_gpe_handler(ACPI_HANDLE, uint32_t, void *); |
165 | static ACPI_STATUS acpiec_space_setup(ACPI_HANDLE, uint32_t, void *, void **); | | 234 | static ACPI_STATUS acpiec_space_setup(ACPI_HANDLE, uint32_t, void *, void **); |
166 | static ACPI_STATUS acpiec_space_handler(uint32_t, ACPI_PHYSICAL_ADDRESS, | | 235 | static ACPI_STATUS acpiec_space_handler(uint32_t, ACPI_PHYSICAL_ADDRESS, |
167 | uint32_t, ACPI_INTEGER *, void *, void *); | | 236 | uint32_t, ACPI_INTEGER *, void *, void *); |
168 | | | 237 | |
169 | static void acpiec_gpe_state_machine(device_t); | | 238 | static void acpiec_gpe_state_machine(struct acpiec_softc *); |
170 | | | 239 | |
171 | CFATTACH_DECL_NEW(acpiec, sizeof(struct acpiec_softc), | | 240 | CFATTACH_DECL_NEW(acpiec, sizeof(struct acpiec_softc), |
172 | acpiec_match, acpiec_attach, NULL, NULL); | | 241 | acpiec_match, acpiec_attach, NULL, NULL); |
173 | | | 242 | |
174 | CFATTACH_DECL_NEW(acpiecdt, sizeof(struct acpiec_softc), | | 243 | CFATTACH_DECL_NEW(acpiecdt, sizeof(struct acpiec_softc), |
175 | acpiecdt_match, acpiecdt_attach, NULL, NULL); | | 244 | acpiecdt_match, acpiecdt_attach, NULL, NULL); |
176 | | | 245 | |
177 | static device_t ec_singleton = NULL; | | 246 | static device_t ec_singleton = NULL; |
178 | static bool acpiec_cold = false; | | 247 | static bool acpiec_cold = false; |
179 | | | 248 | |
180 | static bool | | 249 | static bool |
181 | acpiecdt_find(device_t parent, ACPI_HANDLE *ec_handle, | | 250 | acpiecdt_find(device_t parent, ACPI_HANDLE *ec_handle, |
182 | bus_addr_t *cmd_reg, bus_addr_t *data_reg, uint8_t *gpebit) | | 251 | bus_addr_t *cmd_reg, bus_addr_t *data_reg, uint8_t *gpebit) |
| @@ -303,26 +372,28 @@ fail0: if (!pmf_device_register(self, NU | | | @@ -303,26 +372,28 @@ fail0: if (!pmf_device_register(self, NU |
303 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 372 | aprint_error_dev(self, "couldn't establish power handler\n"); |
304 | } | | 373 | } |
305 | | | 374 | |
306 | static void | | 375 | static void |
307 | acpiec_common_attach(device_t parent, device_t self, | | 376 | acpiec_common_attach(device_t parent, device_t self, |
308 | ACPI_HANDLE ec_handle, bus_space_tag_t cmdt, bus_addr_t cmd_reg, | | 377 | ACPI_HANDLE ec_handle, bus_space_tag_t cmdt, bus_addr_t cmd_reg, |
309 | bus_space_tag_t datat, bus_addr_t data_reg, | | 378 | bus_space_tag_t datat, bus_addr_t data_reg, |
310 | ACPI_HANDLE gpe_handle, uint8_t gpebit) | | 379 | ACPI_HANDLE gpe_handle, uint8_t gpebit) |
311 | { | | 380 | { |
312 | struct acpiec_softc *sc = device_private(self); | | 381 | struct acpiec_softc *sc = device_private(self); |
313 | ACPI_STATUS rv; | | 382 | ACPI_STATUS rv; |
314 | ACPI_INTEGER val; | | 383 | ACPI_INTEGER val; |
315 | | | 384 | |
| | | 385 | sc->sc_dev = self; |
| | | 386 | |
316 | sc->sc_csr_st = cmdt; | | 387 | sc->sc_csr_st = cmdt; |
317 | sc->sc_data_st = datat; | | 388 | sc->sc_data_st = datat; |
318 | | | 389 | |
319 | sc->sc_ech = ec_handle; | | 390 | sc->sc_ech = ec_handle; |
320 | sc->sc_gpeh = gpe_handle; | | 391 | sc->sc_gpeh = gpe_handle; |
321 | sc->sc_gpebit = gpebit; | | 392 | sc->sc_gpebit = gpebit; |
322 | | | 393 | |
323 | sc->sc_state = EC_STATE_FREE; | | 394 | sc->sc_state = EC_STATE_FREE; |
324 | mutex_init(&sc->sc_mtx, MUTEX_DRIVER, IPL_TTY); | | 395 | mutex_init(&sc->sc_mtx, MUTEX_DRIVER, IPL_TTY); |
325 | mutex_init(&sc->sc_access_mtx, MUTEX_DEFAULT, IPL_NONE); | | 396 | mutex_init(&sc->sc_access_mtx, MUTEX_DEFAULT, IPL_NONE); |
326 | cv_init(&sc->sc_cv, "eccv"); | | 397 | cv_init(&sc->sc_cv, "eccv"); |
327 | cv_init(&sc->sc_cv_sci, "ecsci"); | | 398 | cv_init(&sc->sc_cv_sci, "ecsci"); |
328 | | | 399 | |
| @@ -341,54 +412,54 @@ acpiec_common_attach(device_t parent, de | | | @@ -341,54 +412,54 @@ acpiec_common_attach(device_t parent, de |
341 | if (rv == AE_OK) { | | 412 | if (rv == AE_OK) { |
342 | sc->sc_need_global_lock = val != 0; | | 413 | sc->sc_need_global_lock = val != 0; |
343 | } else if (rv != AE_NOT_FOUND) { | | 414 | } else if (rv != AE_NOT_FOUND) { |
344 | aprint_error_dev(self, "unable to evaluate _GLK: %s\n", | | 415 | aprint_error_dev(self, "unable to evaluate _GLK: %s\n", |
345 | AcpiFormatException(rv)); | | 416 | AcpiFormatException(rv)); |
346 | goto post_csr_map; | | 417 | goto post_csr_map; |
347 | } else { | | 418 | } else { |
348 | sc->sc_need_global_lock = false; | | 419 | sc->sc_need_global_lock = false; |
349 | } | | 420 | } |
350 | if (sc->sc_need_global_lock) | | 421 | if (sc->sc_need_global_lock) |
351 | aprint_normal_dev(self, "using global ACPI lock\n"); | | 422 | aprint_normal_dev(self, "using global ACPI lock\n"); |
352 | | | 423 | |
353 | callout_init(&sc->sc_pseudo_intr, CALLOUT_MPSAFE); | | 424 | callout_init(&sc->sc_pseudo_intr, CALLOUT_MPSAFE); |
354 | callout_setfunc(&sc->sc_pseudo_intr, acpiec_callout, self); | | 425 | callout_setfunc(&sc->sc_pseudo_intr, acpiec_callout, sc); |
355 | | | 426 | |
356 | rv = AcpiInstallAddressSpaceHandler(sc->sc_ech, ACPI_ADR_SPACE_EC, | | 427 | rv = AcpiInstallAddressSpaceHandler(sc->sc_ech, ACPI_ADR_SPACE_EC, |
357 | acpiec_space_handler, acpiec_space_setup, self); | | 428 | acpiec_space_handler, acpiec_space_setup, sc); |
358 | if (rv != AE_OK) { | | 429 | if (rv != AE_OK) { |
359 | aprint_error_dev(self, | | 430 | aprint_error_dev(self, |
360 | "unable to install address space handler: %s\n", | | 431 | "unable to install address space handler: %s\n", |
361 | AcpiFormatException(rv)); | | 432 | AcpiFormatException(rv)); |
362 | goto post_csr_map; | | 433 | goto post_csr_map; |
363 | } | | 434 | } |
364 | | | 435 | |
365 | rv = AcpiInstallGpeHandler(sc->sc_gpeh, sc->sc_gpebit, | | 436 | rv = AcpiInstallGpeHandler(sc->sc_gpeh, sc->sc_gpebit, |
366 | ACPI_GPE_EDGE_TRIGGERED, acpiec_gpe_handler, self); | | 437 | ACPI_GPE_EDGE_TRIGGERED, acpiec_gpe_handler, sc); |
367 | if (rv != AE_OK) { | | 438 | if (rv != AE_OK) { |
368 | aprint_error_dev(self, "unable to install GPE handler: %s\n", | | 439 | aprint_error_dev(self, "unable to install GPE handler: %s\n", |
369 | AcpiFormatException(rv)); | | 440 | AcpiFormatException(rv)); |
370 | goto post_csr_map; | | 441 | goto post_csr_map; |
371 | } | | 442 | } |
372 | | | 443 | |
373 | rv = AcpiEnableGpe(sc->sc_gpeh, sc->sc_gpebit); | | 444 | rv = AcpiEnableGpe(sc->sc_gpeh, sc->sc_gpebit); |
374 | if (rv != AE_OK) { | | 445 | if (rv != AE_OK) { |
375 | aprint_error_dev(self, "unable to enable GPE: %s\n", | | 446 | aprint_error_dev(self, "unable to enable GPE: %s\n", |
376 | AcpiFormatException(rv)); | | 447 | AcpiFormatException(rv)); |
377 | goto post_csr_map; | | 448 | goto post_csr_map; |
378 | } | | 449 | } |
379 | | | 450 | |
380 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, acpiec_gpe_query, | | 451 | if (kthread_create(PRI_NONE, KTHREAD_MPSAFE, NULL, acpiec_gpe_query, |
381 | self, NULL, "acpiec sci thread")) { | | 452 | sc, NULL, "acpiec sci thread")) { |
382 | aprint_error_dev(self, "unable to create query kthread\n"); | | 453 | aprint_error_dev(self, "unable to create query kthread\n"); |
383 | goto post_csr_map; | | 454 | goto post_csr_map; |
384 | } | | 455 | } |
385 | | | 456 | |
386 | ec_singleton = self; | | 457 | ec_singleton = self; |
387 | | | 458 | |
388 | if (!pmf_device_register1(self, acpiec_suspend, acpiec_resume, | | 459 | if (!pmf_device_register1(self, acpiec_suspend, acpiec_resume, |
389 | acpiec_shutdown)) | | 460 | acpiec_shutdown)) |
390 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 461 | aprint_error_dev(self, "couldn't establish power handler\n"); |
391 | | | 462 | |
392 | return; | | 463 | return; |
393 | | | 464 | |
394 | post_csr_map: | | 465 | post_csr_map: |
| @@ -396,46 +467,68 @@ post_csr_map: | | | @@ -396,46 +467,68 @@ post_csr_map: |
396 | acpiec_gpe_handler); | | 467 | acpiec_gpe_handler); |
397 | (void)AcpiRemoveAddressSpaceHandler(sc->sc_ech, | | 468 | (void)AcpiRemoveAddressSpaceHandler(sc->sc_ech, |
398 | ACPI_ADR_SPACE_EC, acpiec_space_handler); | | 469 | ACPI_ADR_SPACE_EC, acpiec_space_handler); |
399 | bus_space_unmap(sc->sc_csr_st, sc->sc_csr_sh, 1); | | 470 | bus_space_unmap(sc->sc_csr_st, sc->sc_csr_sh, 1); |
400 | post_data_map: | | 471 | post_data_map: |
401 | bus_space_unmap(sc->sc_data_st, sc->sc_data_sh, 1); | | 472 | bus_space_unmap(sc->sc_data_st, sc->sc_data_sh, 1); |
402 | if (!pmf_device_register(self, NULL, NULL)) | | 473 | if (!pmf_device_register(self, NULL, NULL)) |
403 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 474 | aprint_error_dev(self, "couldn't establish power handler\n"); |
404 | } | | 475 | } |
405 | | | 476 | |
406 | static bool | | 477 | static bool |
407 | acpiec_suspend(device_t dv, const pmf_qual_t *qual) | | 478 | acpiec_suspend(device_t dv, const pmf_qual_t *qual) |
408 | { | | 479 | { |
| | | 480 | struct acpiec_softc *sc = device_private(dv); |
409 | | | 481 | |
| | | 482 | /* |
| | | 483 | * XXX This looks bad because acpiec_cold is global and |
| | | 484 | * sc->sc_mtx doesn't look like it's global, but we can have |
| | | 485 | * only one acpiec(4) device anyway. Maybe acpiec_cold should |
| | | 486 | * live in the softc to make this look less bad? |
| | | 487 | * |
| | | 488 | * XXX Should this block read/write/query transactions until |
| | | 489 | * resume? |
| | | 490 | * |
| | | 491 | * XXX Should this interrupt existing transactions to make them |
| | | 492 | * fail promptly or restart on resume? |
| | | 493 | */ |
| | | 494 | mutex_enter(&sc->sc_mtx); |
410 | acpiec_cold = true; | | 495 | acpiec_cold = true; |
| | | 496 | mutex_exit(&sc->sc_mtx); |
411 | | | 497 | |
412 | return true; | | 498 | return true; |
413 | } | | 499 | } |
414 | | | 500 | |
415 | static bool | | 501 | static bool |
416 | acpiec_resume(device_t dv, const pmf_qual_t *qual) | | 502 | acpiec_resume(device_t dv, const pmf_qual_t *qual) |
417 | { | | 503 | { |
| | | 504 | struct acpiec_softc *sc = device_private(dv); |
418 | | | 505 | |
| | | 506 | mutex_enter(&sc->sc_mtx); |
419 | acpiec_cold = false; | | 507 | acpiec_cold = false; |
| | | 508 | mutex_exit(&sc->sc_mtx); |
420 | | | 509 | |
421 | return true; | | 510 | return true; |
422 | } | | 511 | } |
423 | | | 512 | |
424 | static bool | | 513 | static bool |
425 | acpiec_shutdown(device_t dv, int how) | | 514 | acpiec_shutdown(device_t dv, int how) |
426 | { | | 515 | { |
| | | 516 | struct acpiec_softc *sc = device_private(dv); |
427 | | | 517 | |
| | | 518 | mutex_enter(&sc->sc_mtx); |
428 | acpiec_cold = true; | | 519 | acpiec_cold = true; |
| | | 520 | mutex_exit(&sc->sc_mtx); |
| | | 521 | |
429 | return true; | | 522 | return true; |
430 | } | | 523 | } |
431 | | | 524 | |
432 | static bool | | 525 | static bool |
433 | acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle, | | 526 | acpiec_parse_gpe_package(device_t self, ACPI_HANDLE ec_handle, |
434 | ACPI_HANDLE *gpe_handle, uint8_t *gpebit) | | 527 | ACPI_HANDLE *gpe_handle, uint8_t *gpebit) |
435 | { | | 528 | { |
436 | ACPI_BUFFER buf; | | 529 | ACPI_BUFFER buf; |
437 | ACPI_OBJECT *p, *c; | | 530 | ACPI_OBJECT *p, *c; |
438 | ACPI_STATUS rv; | | 531 | ACPI_STATUS rv; |
439 | | | 532 | |
440 | rv = acpi_eval_struct(ec_handle, "_GPE", &buf); | | 533 | rv = acpi_eval_struct(ec_handle, "_GPE", &buf); |
441 | if (rv != AE_OK) { | | 534 | if (rv != AE_OK) { |
| @@ -481,197 +574,244 @@ acpiec_parse_gpe_package(device_t self, | | | @@ -481,197 +574,244 @@ acpiec_parse_gpe_package(device_t self, |
481 | aprint_error_dev(self, | | 574 | aprint_error_dev(self, |
482 | "_GPE package needs integer as 2nd field\n"); | | 575 | "_GPE package needs integer as 2nd field\n"); |
483 | ACPI_FREE(p); | | 576 | ACPI_FREE(p); |
484 | return false; | | 577 | return false; |
485 | } | | 578 | } |
486 | *gpebit = c->Integer.Value; | | 579 | *gpebit = c->Integer.Value; |
487 | ACPI_FREE(p); | | 580 | ACPI_FREE(p); |
488 | return true; | | 581 | return true; |
489 | } | | 582 | } |
490 | | | 583 | |
491 | static uint8_t | | 584 | static uint8_t |
492 | acpiec_read_data(struct acpiec_softc *sc) | | 585 | acpiec_read_data(struct acpiec_softc *sc) |
493 | { | | 586 | { |
494 | return bus_space_read_1(sc->sc_data_st, sc->sc_data_sh, 0); | | 587 | uint8_t x; |
| | | 588 | |
| | | 589 | KASSERT(mutex_owned(&sc->sc_mtx)); |
| | | 590 | |
| | | 591 | x = bus_space_read_1(sc->sc_data_st, sc->sc_data_sh, 0); |
| | | 592 | DPRINTF(ACPIEC_DEBUG_REG, sc, "read data=0x%"PRIx8"\n", x); |
| | | 593 | |
| | | 594 | return x; |
495 | } | | 595 | } |
496 | | | 596 | |
497 | static void | | 597 | static void |
498 | acpiec_write_data(struct acpiec_softc *sc, uint8_t val) | | 598 | acpiec_write_data(struct acpiec_softc *sc, uint8_t val) |
499 | { | | 599 | { |
| | | 600 | |
| | | 601 | KASSERT(mutex_owned(&sc->sc_mtx)); |
| | | 602 | |
| | | 603 | DPRINTF(ACPIEC_DEBUG_REG, sc, "write data=0x%"PRIx8"\n", val); |
500 | bus_space_write_1(sc->sc_data_st, sc->sc_data_sh, 0, val); | | 604 | bus_space_write_1(sc->sc_data_st, sc->sc_data_sh, 0, val); |
501 | } | | 605 | } |
502 | | | 606 | |
503 | static uint8_t | | 607 | static uint8_t |
504 | acpiec_read_status(struct acpiec_softc *sc) | | 608 | acpiec_read_status(struct acpiec_softc *sc) |
505 | { | | 609 | { |
506 | return bus_space_read_1(sc->sc_csr_st, sc->sc_csr_sh, 0); | | 610 | uint8_t x; |
| | | 611 | |
| | | 612 | KASSERT(mutex_owned(&sc->sc_mtx)); |
| | | 613 | |
| | | 614 | x = bus_space_read_1(sc->sc_csr_st, sc->sc_csr_sh, 0); |
| | | 615 | DPRINTF(ACPIEC_DEBUG_REG, sc, "read status=0x%"PRIx8"\n", x); |
| | | 616 | |
| | | 617 | return x; |
507 | } | | 618 | } |
508 | | | 619 | |
509 | static void | | 620 | static void |
510 | acpiec_write_command(struct acpiec_softc *sc, uint8_t cmd) | | 621 | acpiec_write_command(struct acpiec_softc *sc, uint8_t cmd) |
511 | { | | 622 | { |
| | | 623 | |
| | | 624 | KASSERT(mutex_owned(&sc->sc_mtx)); |
| | | 625 | |
| | | 626 | DPRINTF(ACPIEC_DEBUG_REG, sc, "write command=0x%"PRIx8"\n", cmd); |
512 | bus_space_write_1(sc->sc_csr_st, sc->sc_csr_sh, 0, cmd); | | 627 | bus_space_write_1(sc->sc_csr_st, sc->sc_csr_sh, 0, cmd); |
513 | } | | 628 | } |
514 | | | 629 | |
515 | static ACPI_STATUS | | 630 | static ACPI_STATUS |
516 | acpiec_space_setup(ACPI_HANDLE region, uint32_t func, void *arg, | | 631 | acpiec_space_setup(ACPI_HANDLE region, uint32_t func, void *arg, |
517 | void **region_arg) | | 632 | void **region_arg) |
518 | { | | 633 | { |
519 | | | 634 | |
520 | if (func == ACPI_REGION_DEACTIVATE) | | 635 | if (func == ACPI_REGION_DEACTIVATE) |
521 | *region_arg = NULL; | | 636 | *region_arg = NULL; |
522 | else | | 637 | else |
523 | *region_arg = arg; | | 638 | *region_arg = arg; |
524 | | | 639 | |
525 | return AE_OK; | | 640 | return AE_OK; |
526 | } | | 641 | } |
527 | | | 642 | |
528 | static void | | 643 | static void |
529 | acpiec_lock(device_t dv) | | 644 | acpiec_lock(struct acpiec_softc *sc) |
530 | { | | 645 | { |
531 | struct acpiec_softc *sc = device_private(dv); | | | |
532 | ACPI_STATUS rv; | | 646 | ACPI_STATUS rv; |
533 | | | 647 | |
534 | mutex_enter(&sc->sc_access_mtx); | | 648 | mutex_enter(&sc->sc_access_mtx); |
535 | | | 649 | |
536 | if (sc->sc_need_global_lock) { | | 650 | if (sc->sc_need_global_lock) { |
537 | rv = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, | | 651 | rv = AcpiAcquireGlobalLock(EC_LOCK_TIMEOUT, |
538 | &sc->sc_global_lock); | | 652 | &sc->sc_global_lock); |
539 | if (rv != AE_OK) { | | 653 | if (rv != AE_OK) { |
540 | aprint_error_dev(dv, | | 654 | aprint_error_dev(sc->sc_dev, |
541 | "failed to acquire global lock: %s\n", | | 655 | "failed to acquire global lock: %s\n", |
542 | AcpiFormatException(rv)); | | 656 | AcpiFormatException(rv)); |
543 | return; | | 657 | return; |
544 | } | | 658 | } |
545 | } | | 659 | } |
546 | } | | 660 | } |
547 | | | 661 | |
548 | static void | | 662 | static void |
549 | acpiec_unlock(device_t dv) | | 663 | acpiec_unlock(struct acpiec_softc *sc) |
550 | { | | 664 | { |
551 | struct acpiec_softc *sc = device_private(dv); | | | |
552 | ACPI_STATUS rv; | | 665 | ACPI_STATUS rv; |
553 | | | 666 | |
554 | if (sc->sc_need_global_lock) { | | 667 | if (sc->sc_need_global_lock) { |
555 | rv = AcpiReleaseGlobalLock(sc->sc_global_lock); | | 668 | rv = AcpiReleaseGlobalLock(sc->sc_global_lock); |
556 | if (rv != AE_OK) { | | 669 | if (rv != AE_OK) { |
557 | aprint_error_dev(dv, | | 670 | aprint_error_dev(sc->sc_dev, |
558 | "failed to release global lock: %s\n", | | 671 | "failed to release global lock: %s\n", |
559 | AcpiFormatException(rv)); | | 672 | AcpiFormatException(rv)); |
560 | } | | 673 | } |
561 | } | | 674 | } |
562 | mutex_exit(&sc->sc_access_mtx); | | 675 | mutex_exit(&sc->sc_access_mtx); |
563 | } | | 676 | } |
564 | | | 677 | |
565 | static ACPI_STATUS | | 678 | static ACPI_STATUS |
566 | acpiec_read(device_t dv, uint8_t addr, uint8_t *val) | | 679 | acpiec_wait_timeout(struct acpiec_softc *sc) |
567 | { | | 680 | { |
568 | struct acpiec_softc *sc = device_private(dv); | | 681 | device_t dv = sc->sc_dev; |
569 | int i, timeo = 1000 * EC_CMD_TIMEOUT; | | 682 | int i; |
570 | | | | |
571 | acpiec_lock(dv); | | | |
572 | mutex_enter(&sc->sc_mtx); | | | |
573 | | | | |
574 | sc->sc_cur_addr = addr; | | | |
575 | sc->sc_state = EC_STATE_READ; | | | |
576 | | | 683 | |
577 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { | | 684 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { |
578 | acpiec_gpe_state_machine(dv); | | 685 | acpiec_gpe_state_machine(sc); |
579 | if (sc->sc_state == EC_STATE_FREE) | | 686 | if (sc->sc_state == EC_STATE_FREE) |
580 | goto done; | | 687 | return AE_OK; |
581 | delay(1); | | 688 | delay(1); |
582 | } | | 689 | } |
583 | | | 690 | |
| | | 691 | DPRINTF(ACPIEC_DEBUG_RW, sc, "SCI polling timeout\n"); |
584 | if (cold || acpiec_cold) { | | 692 | if (cold || acpiec_cold) { |
| | | 693 | int timeo = 1000 * EC_CMD_TIMEOUT; |
| | | 694 | |
585 | while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { | | 695 | while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { |
586 | delay(1000); | | 696 | delay(1000); |
587 | acpiec_gpe_state_machine(dv); | | 697 | acpiec_gpe_state_machine(sc); |
588 | } | | 698 | } |
589 | if (sc->sc_state != EC_STATE_FREE) { | | 699 | if (sc->sc_state != EC_STATE_FREE) { |
590 | mutex_exit(&sc->sc_mtx); | | | |
591 | acpiec_unlock(dv); | | | |
592 | aprint_error_dev(dv, "command timed out, state %d\n", | | 700 | aprint_error_dev(dv, "command timed out, state %d\n", |
593 | sc->sc_state); | | 701 | sc->sc_state); |
594 | return AE_ERROR; | | 702 | return AE_ERROR; |
595 | } | | 703 | } |
596 | } else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) { | | 704 | } else { |
597 | mutex_exit(&sc->sc_mtx); | | 705 | const unsigned deadline = getticks() + EC_CMD_TIMEOUT*hz; |
598 | acpiec_unlock(dv); | | 706 | unsigned delta; |
599 | aprint_error_dev(dv, | | 707 | |
600 | "command takes over %d sec...\n", EC_CMD_TIMEOUT); | | 708 | while (sc->sc_state != EC_STATE_FREE && |
601 | return AE_ERROR; | | 709 | (delta = deadline - getticks()) < INT_MAX) |
| | | 710 | (void)cv_timedwait(&sc->sc_cv, &sc->sc_mtx, delta); |
| | | 711 | if (sc->sc_state != EC_STATE_FREE) { |
| | | 712 | aprint_error_dev(dv, |
| | | 713 | "command takes over %d sec...\n", |
| | | 714 | EC_CMD_TIMEOUT); |
| | | 715 | return AE_ERROR; |
| | | 716 | } |
602 | } | | 717 | } |
603 | | | 718 | |
604 | done: | | 719 | return AE_OK; |
| | | 720 | } |
| | | 721 | |
| | | 722 | static ACPI_STATUS |
| | | 723 | acpiec_read(struct acpiec_softc *sc, uint8_t addr, uint8_t *val) |
| | | 724 | { |
| | | 725 | ACPI_STATUS rv; |
| | | 726 | |
| | | 727 | acpiec_lock(sc); |
| | | 728 | mutex_enter(&sc->sc_mtx); |
| | | 729 | |
| | | 730 | DPRINTF(ACPIEC_DEBUG_RW, sc, |
| | | 731 | "pid %ld %s, lid %ld%s%s: read addr 0x%"PRIx8"\n", |
| | | 732 | (long)curproc->p_pid, curproc->p_comm, |
| | | 733 | (long)curlwp->l_lid, curlwp->l_name ? " " : "", |
| | | 734 | curlwp->l_name ? curlwp->l_name : "", |
| | | 735 | addr); |
| | | 736 | |
| | | 737 | KASSERT(sc->sc_state == EC_STATE_FREE); |
| | | 738 | |
| | | 739 | sc->sc_cur_addr = addr; |
| | | 740 | sc->sc_state = EC_STATE_READ; |
| | | 741 | |
| | | 742 | rv = acpiec_wait_timeout(sc); |
| | | 743 | if (ACPI_FAILURE(rv)) |
| | | 744 | goto out; |
| | | 745 | |
| | | 746 | DPRINTF(ACPIEC_DEBUG_RW, sc, |
| | | 747 | "pid %ld %s, lid %ld%s%s: read addr 0x%"PRIx8": 0x%"PRIx8"\n", |
| | | 748 | (long)curproc->p_pid, curproc->p_comm, |
| | | 749 | (long)curlwp->l_lid, curlwp->l_name ? " " : "", |
| | | 750 | curlwp->l_name ? curlwp->l_name : "", |
| | | 751 | addr, sc->sc_cur_val); |
| | | 752 | |
605 | *val = sc->sc_cur_val; | | 753 | *val = sc->sc_cur_val; |
606 | | | 754 | |
607 | mutex_exit(&sc->sc_mtx); | | 755 | out: mutex_exit(&sc->sc_mtx); |
608 | acpiec_unlock(dv); | | 756 | acpiec_unlock(sc); |
609 | return AE_OK; | | 757 | return rv; |
610 | } | | 758 | } |
611 | | | 759 | |
612 | static ACPI_STATUS | | 760 | static ACPI_STATUS |
613 | acpiec_write(device_t dv, uint8_t addr, uint8_t val) | | 761 | acpiec_write(struct acpiec_softc *sc, uint8_t addr, uint8_t val) |
614 | { | | 762 | { |
615 | struct acpiec_softc *sc = device_private(dv); | | 763 | ACPI_STATUS rv; |
616 | int i, timeo = 1000 * EC_CMD_TIMEOUT; | | | |
617 | | | 764 | |
618 | acpiec_lock(dv); | | 765 | acpiec_lock(sc); |
619 | mutex_enter(&sc->sc_mtx); | | 766 | mutex_enter(&sc->sc_mtx); |
620 | | | 767 | |
| | | 768 | DPRINTF(ACPIEC_DEBUG_RW, sc, |
| | | 769 | "pid %ld %s, lid %ld%s%s write addr 0x%"PRIx8": 0x%"PRIx8"\n", |
| | | 770 | (long)curproc->p_pid, curproc->p_comm, |
| | | 771 | (long)curlwp->l_lid, curlwp->l_name ? " " : "", |
| | | 772 | curlwp->l_name ? curlwp->l_name : "", |
| | | 773 | addr, val); |
| | | 774 | |
| | | 775 | KASSERT(sc->sc_state == EC_STATE_FREE); |
| | | 776 | |
621 | sc->sc_cur_addr = addr; | | 777 | sc->sc_cur_addr = addr; |
622 | sc->sc_cur_val = val; | | 778 | sc->sc_cur_val = val; |
623 | sc->sc_state = EC_STATE_WRITE; | | 779 | sc->sc_state = EC_STATE_WRITE; |
624 | | | 780 | |
625 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { | | 781 | rv = acpiec_wait_timeout(sc); |
626 | acpiec_gpe_state_machine(dv); | | 782 | if (ACPI_FAILURE(rv)) |
627 | if (sc->sc_state == EC_STATE_FREE) | | 783 | goto out; |
628 | goto done; | | | |
629 | delay(1); | | | |
630 | } | | | |
631 | | | 784 | |
632 | if (cold || acpiec_cold) { | | 785 | DPRINTF(ACPIEC_DEBUG_RW, sc, |
633 | while (sc->sc_state != EC_STATE_FREE && timeo-- > 0) { | | 786 | "pid %ld %s, lid %ld%s%s: write addr 0x%"PRIx8": 0x%"PRIx8 |
634 | delay(1000); | | 787 | " done\n", |
635 | acpiec_gpe_state_machine(dv); | | 788 | (long)curproc->p_pid, curproc->p_comm, |
636 | } | | 789 | (long)curlwp->l_lid, curlwp->l_name ? " " : "", |
637 | if (sc->sc_state != EC_STATE_FREE) { | | 790 | curlwp->l_name ? curlwp->l_name : "", |
638 | mutex_exit(&sc->sc_mtx); | | 791 | addr, val); |
639 | acpiec_unlock(dv); | | | |
640 | aprint_error_dev(dv, "command timed out, state %d\n", | | | |
641 | sc->sc_state); | | | |
642 | return AE_ERROR; | | | |
643 | } | | | |
644 | } else if (cv_timedwait(&sc->sc_cv, &sc->sc_mtx, EC_CMD_TIMEOUT * hz)) { | | | |
645 | mutex_exit(&sc->sc_mtx); | | | |
646 | acpiec_unlock(dv); | | | |
647 | aprint_error_dev(dv, | | | |
648 | "command takes over %d sec...\n", EC_CMD_TIMEOUT); | | | |
649 | return AE_ERROR; | | | |
650 | } | | | |
651 | | | 792 | |
652 | done: | | 793 | out: mutex_exit(&sc->sc_mtx); |
653 | mutex_exit(&sc->sc_mtx); | | 794 | acpiec_unlock(sc); |
654 | acpiec_unlock(dv); | | 795 | return rv; |
655 | return AE_OK; | | | |
656 | } | | 796 | } |
657 | | | 797 | |
658 | /* | | 798 | /* |
659 | * acpiec_space_handler(func, paddr, bitwidth, value, arg, region_arg) | | 799 | * acpiec_space_handler(func, paddr, bitwidth, value, arg, region_arg) |
660 | * | | 800 | * |
661 | * Transfer bitwidth/8 bytes of data between paddr and *value: | | 801 | * Transfer bitwidth/8 bytes of data between paddr and *value: |
662 | * from paddr to *value when func is ACPI_READ, and the other way | | 802 | * from paddr to *value when func is ACPI_READ, and the other way |
663 | * when func is ACPI_WRITE. arg is the acpiec(4) or acpiecdt(4) | | 803 | * when func is ACPI_WRITE. arg is the acpiec_softc pointer. |
664 | * device. region_arg is ignored (XXX why? determined by | | 804 | * region_arg is ignored (XXX why? determined by |
665 | * acpiec_space_setup but never used by anything that I can see). | | 805 | * acpiec_space_setup but never used by anything that I can see). |
666 | * | | 806 | * |
667 | * The caller always provides storage at *value large enough for | | 807 | * The caller always provides storage at *value large enough for |
668 | * an ACPI_INTEGER object, i.e., a 64-bit integer. However, | | 808 | * an ACPI_INTEGER object, i.e., a 64-bit integer. However, |
669 | * bitwidth may be larger; in this case the caller provides larger | | 809 | * bitwidth may be larger; in this case the caller provides larger |
670 | * storage at *value, e.g. 128 bits as documented in | | 810 | * storage at *value, e.g. 128 bits as documented in |
671 | * <https://gnats.netbsd.org/55206>. | | 811 | * <https://gnats.netbsd.org/55206>. |
672 | * | | 812 | * |
673 | * On reads, this fully initializes one ACPI_INTEGER's worth of | | 813 | * On reads, this fully initializes one ACPI_INTEGER's worth of |
674 | * data at *value, even if bitwidth < 64. The integer is | | 814 | * data at *value, even if bitwidth < 64. The integer is |
675 | * interpreted in host byte order; in other words, bytes of data | | 815 | * interpreted in host byte order; in other words, bytes of data |
676 | * are transferred in order between paddr and (uint8_t *)value. | | 816 | * are transferred in order between paddr and (uint8_t *)value. |
677 | * The transfer is not atomic; it may go byte-by-byte. | | 817 | * The transfer is not atomic; it may go byte-by-byte. |
| @@ -681,247 +821,298 @@ done: | | | @@ -681,247 +821,298 @@ done: |
681 | * in the low-order bits of the result. A big-endian system could | | 821 | * in the low-order bits of the result. A big-endian system could |
682 | * read a 64-bit integer in big-endian (and it did for a while!), | | 822 | * read a 64-bit integer in big-endian (and it did for a while!), |
683 | * but what should it do for larger reads? Unclear! | | 823 | * but what should it do for larger reads? Unclear! |
684 | * | | 824 | * |
685 | * XXX It's not clear whether the object at *value is always | | 825 | * XXX It's not clear whether the object at *value is always |
686 | * _aligned_ adequately for an ACPI_INTEGER object. Currently it | | 826 | * _aligned_ adequately for an ACPI_INTEGER object. Currently it |
687 | * always is as long as malloc, used by AcpiOsAllocate, returns | | 827 | * always is as long as malloc, used by AcpiOsAllocate, returns |
688 | * 64-bit-aligned data. | | 828 | * 64-bit-aligned data. |
689 | */ | | 829 | */ |
690 | static ACPI_STATUS | | 830 | static ACPI_STATUS |
691 | acpiec_space_handler(uint32_t func, ACPI_PHYSICAL_ADDRESS paddr, | | 831 | acpiec_space_handler(uint32_t func, ACPI_PHYSICAL_ADDRESS paddr, |
692 | uint32_t width, ACPI_INTEGER *value, void *arg, void *region_arg) | | 832 | uint32_t width, ACPI_INTEGER *value, void *arg, void *region_arg) |
693 | { | | 833 | { |
694 | device_t dv; | | 834 | struct acpiec_softc *sc = arg; |
695 | ACPI_STATUS rv; | | 835 | ACPI_STATUS rv; |
696 | uint8_t addr, *buf; | | 836 | uint8_t addr, *buf; |
697 | unsigned int i; | | 837 | unsigned int i; |
698 | | | 838 | |
699 | if (paddr > 0xff || width % 8 != 0 || | | 839 | if (paddr > 0xff || width % 8 != 0 || |
700 | value == NULL || arg == NULL || paddr + width / 8 > 0x100) | | 840 | value == NULL || arg == NULL || paddr + width / 8 > 0x100) |
701 | return AE_BAD_PARAMETER; | | 841 | return AE_BAD_PARAMETER; |
702 | | | 842 | |
703 | addr = paddr; | | 843 | addr = paddr; |
704 | dv = arg; | | | |
705 | buf = (uint8_t *)value; | | 844 | buf = (uint8_t *)value; |
706 | | | 845 | |
707 | rv = AE_OK; | | 846 | rv = AE_OK; |
708 | | | 847 | |
709 | switch (func) { | | 848 | switch (func) { |
710 | case ACPI_READ: | | 849 | case ACPI_READ: |
711 | for (i = 0; i < width; i += 8, ++addr, ++buf) { | | 850 | for (i = 0; i < width; i += 8, ++addr, ++buf) { |
712 | rv = acpiec_read(dv, addr, buf); | | 851 | rv = acpiec_read(sc, addr, buf); |
713 | if (rv != AE_OK) | | 852 | if (rv != AE_OK) |
714 | break; | | 853 | break; |
715 | } | | 854 | } |
716 | /* | | 855 | /* |
717 | * Make sure to fully initialize at least an | | 856 | * Make sure to fully initialize at least an |
718 | * ACPI_INTEGER-sized object. | | 857 | * ACPI_INTEGER-sized object. |
719 | */ | | 858 | */ |
720 | for (; i < sizeof(*value)*8; i += 8, ++buf) | | 859 | for (; i < sizeof(*value)*8; i += 8, ++buf) |
721 | *buf = 0; | | 860 | *buf = 0; |
722 | break; | | 861 | break; |
723 | case ACPI_WRITE: | | 862 | case ACPI_WRITE: |
724 | for (i = 0; i < width; i += 8, ++addr, ++buf) { | | 863 | for (i = 0; i < width; i += 8, ++addr, ++buf) { |
725 | rv = acpiec_write(dv, addr, *buf); | | 864 | rv = acpiec_write(sc, addr, *buf); |
726 | if (rv != AE_OK) | | 865 | if (rv != AE_OK) |
727 | break; | | 866 | break; |
728 | } | | 867 | } |
729 | break; | | 868 | break; |
730 | default: | | 869 | default: |
731 | aprint_error("%s: invalid Address Space function called: %x\n", | | 870 | aprint_error_dev(sc->sc_dev, |
732 | device_xname(dv), (unsigned int)func); | | 871 | "invalid Address Space function called: %x\n", |
| | | 872 | (unsigned int)func); |
733 | return AE_BAD_PARAMETER; | | 873 | return AE_BAD_PARAMETER; |
734 | } | | 874 | } |
735 | | | 875 | |
736 | return rv; | | 876 | return rv; |
737 | } | | 877 | } |
738 | | | 878 | |
739 | static void | | 879 | static void |
| | | 880 | acpiec_wait(struct acpiec_softc *sc) |
| | | 881 | { |
| | | 882 | int i; |
| | | 883 | |
| | | 884 | /* |
| | | 885 | * First, attempt to get the query by polling. |
| | | 886 | */ |
| | | 887 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { |
| | | 888 | acpiec_gpe_state_machine(sc); |
| | | 889 | if (sc->sc_state == EC_STATE_FREE) |
| | | 890 | return; |
| | | 891 | delay(1); |
| | | 892 | } |
| | | 893 | |
| | | 894 | /* |
| | | 895 | * Polling timed out. Try waiting for interrupts -- either GPE |
| | | 896 | * interrupts, or periodic callouts in case GPE interrupts are |
| | | 897 | * broken. |
| | | 898 | */ |
| | | 899 | DPRINTF(ACPIEC_DEBUG_QUERY, sc, "SCI polling timeout\n"); |
| | | 900 | while (sc->sc_state != EC_STATE_FREE) |
| | | 901 | cv_wait(&sc->sc_cv, &sc->sc_mtx); |
| | | 902 | } |
| | | 903 | |
| | | 904 | static void |
740 | acpiec_gpe_query(void *arg) | | 905 | acpiec_gpe_query(void *arg) |
741 | { | | 906 | { |
742 | device_t dv = arg; | | 907 | struct acpiec_softc *sc = arg; |
743 | struct acpiec_softc *sc = device_private(dv); | | | |
744 | uint8_t reg; | | 908 | uint8_t reg; |
745 | char qxx[5]; | | 909 | char qxx[5]; |
746 | ACPI_STATUS rv; | | 910 | ACPI_STATUS rv; |
747 | int i; | | | |
748 | | | 911 | |
749 | loop: | | 912 | loop: |
| | | 913 | /* |
| | | 914 | * Wait until the EC sends an SCI requesting a query. |
| | | 915 | */ |
750 | mutex_enter(&sc->sc_mtx); | | 916 | mutex_enter(&sc->sc_mtx); |
751 | | | 917 | while (!sc->sc_got_sci) |
752 | if (sc->sc_got_sci == false) | | | |
753 | cv_wait(&sc->sc_cv_sci, &sc->sc_mtx); | | 918 | cv_wait(&sc->sc_cv_sci, &sc->sc_mtx); |
| | | 919 | DPRINTF(ACPIEC_DEBUG_QUERY, sc, "SCI query requested\n"); |
754 | mutex_exit(&sc->sc_mtx); | | 920 | mutex_exit(&sc->sc_mtx); |
755 | | | 921 | |
756 | acpiec_lock(dv); | | 922 | /* |
| | | 923 | * EC wants to submit a query to us. Exclude concurrent reads |
| | | 924 | * and writes while we handle it. |
| | | 925 | */ |
| | | 926 | acpiec_lock(sc); |
757 | mutex_enter(&sc->sc_mtx); | | 927 | mutex_enter(&sc->sc_mtx); |
758 | | | 928 | |
| | | 929 | DPRINTF(ACPIEC_DEBUG_QUERY, sc, "SCI query\n"); |
| | | 930 | |
| | | 931 | KASSERT(sc->sc_state == EC_STATE_FREE); |
| | | 932 | |
759 | /* The Query command can always be issued, so be defensive here. */ | | 933 | /* The Query command can always be issued, so be defensive here. */ |
| | | 934 | KASSERT(sc->sc_got_sci); |
760 | sc->sc_got_sci = false; | | 935 | sc->sc_got_sci = false; |
761 | sc->sc_state = EC_STATE_QUERY; | | 936 | sc->sc_state = EC_STATE_QUERY; |
762 | | | 937 | |
763 | for (i = 0; i < EC_POLL_TIMEOUT; ++i) { | | 938 | acpiec_wait(sc); |
764 | acpiec_gpe_state_machine(dv); | | | |
765 | if (sc->sc_state == EC_STATE_FREE) | | | |
766 | goto done; | | | |
767 | delay(1); | | | |
768 | } | | | |
769 | | | | |
770 | cv_wait(&sc->sc_cv, &sc->sc_mtx); | | | |
771 | | | 939 | |
772 | done: | | | |
773 | reg = sc->sc_cur_val; | | 940 | reg = sc->sc_cur_val; |
| | | 941 | DPRINTF(ACPIEC_DEBUG_QUERY, sc, "SCI query: 0x%"PRIx8"\n", reg); |
774 | | | 942 | |
775 | mutex_exit(&sc->sc_mtx); | | 943 | mutex_exit(&sc->sc_mtx); |
776 | acpiec_unlock(dv); | | 944 | acpiec_unlock(sc); |
777 | | | 945 | |
778 | if (reg == 0) | | 946 | if (reg == 0) |
779 | goto loop; /* Spurious query result */ | | 947 | goto loop; /* Spurious query result */ |
780 | | | 948 | |
781 | /* | | 949 | /* |
782 | * Evaluate _Qxx to respond to the controller. | | 950 | * Evaluate _Qxx to respond to the controller. |
783 | */ | | 951 | */ |
784 | snprintf(qxx, sizeof(qxx), "_Q%02X", (unsigned int)reg); | | 952 | snprintf(qxx, sizeof(qxx), "_Q%02X", (unsigned int)reg); |
785 | rv = AcpiEvaluateObject(sc->sc_ech, qxx, NULL, NULL); | | 953 | rv = AcpiEvaluateObject(sc->sc_ech, qxx, NULL, NULL); |
786 | if (rv != AE_OK && rv != AE_NOT_FOUND) { | | 954 | if (rv != AE_OK && rv != AE_NOT_FOUND) { |
787 | aprint_error_dev(dv, "GPE query method %s failed: %s", | | 955 | aprint_error_dev(sc->sc_dev, "GPE query method %s failed: %s", |
788 | qxx, AcpiFormatException(rv)); | | 956 | qxx, AcpiFormatException(rv)); |
789 | } | | 957 | } |
790 | | | 958 | |
791 | goto loop; | | 959 | goto loop; |
792 | } | | 960 | } |
793 | | | 961 | |
794 | static void | | 962 | static void |
795 | acpiec_gpe_state_machine(device_t dv) | | 963 | acpiec_gpe_state_machine(struct acpiec_softc *sc) |
796 | { | | 964 | { |
797 | struct acpiec_softc *sc = device_private(dv); | | | |
798 | uint8_t reg; | | 965 | uint8_t reg; |
799 | | | 966 | |
| | | 967 | KASSERT(mutex_owned(&sc->sc_mtx)); |
| | | 968 | |
800 | reg = acpiec_read_status(sc); | | 969 | reg = acpiec_read_status(sc); |
801 | | | 970 | |
802 | if (reg & EC_STATUS_SCI) | | 971 | #ifdef ACPIEC_DEBUG |
803 | sc->sc_got_sci = true; | | 972 | if (acpiec_debug & __BIT(ACPIEC_DEBUG_TRANSITION)) { |
| | | 973 | char buf[128]; |
| | | 974 | |
| | | 975 | snprintb(buf, sizeof(buf), EC_STATUS_FMT, reg); |
| | | 976 | DPRINTF(ACPIEC_DEBUG_TRANSITION, sc, "%s\n", buf); |
| | | 977 | } |
| | | 978 | #endif |
804 | | | 979 | |
805 | switch (sc->sc_state) { | | 980 | switch (sc->sc_state) { |
806 | case EC_STATE_QUERY: | | 981 | case EC_STATE_QUERY: |
807 | if ((reg & EC_STATUS_IBF) != 0) | | 982 | if ((reg & EC_STATUS_IBF) != 0) |
808 | break; /* Nothing of interest here. */ | | 983 | break; /* Nothing of interest here. */ |
809 | acpiec_write_command(sc, EC_COMMAND_QUERY); | | 984 | acpiec_write_command(sc, EC_COMMAND_QUERY); |
810 | sc->sc_state = EC_STATE_QUERY_VAL; | | 985 | sc->sc_state = EC_STATE_QUERY_VAL; |
811 | break; | | 986 | break; |
812 | | | 987 | |
813 | case EC_STATE_QUERY_VAL: | | 988 | case EC_STATE_QUERY_VAL: |
814 | if ((reg & EC_STATUS_OBF) == 0) | | 989 | if ((reg & EC_STATUS_OBF) == 0) |
815 | break; /* Nothing of interest here. */ | | 990 | break; /* Nothing of interest here. */ |
816 | | | | |
817 | sc->sc_cur_val = acpiec_read_data(sc); | | 991 | sc->sc_cur_val = acpiec_read_data(sc); |
818 | sc->sc_state = EC_STATE_FREE; | | 992 | sc->sc_state = EC_STATE_FREE; |
819 | | | | |
820 | cv_signal(&sc->sc_cv); | | | |
821 | break; | | 993 | break; |
822 | | | 994 | |
823 | case EC_STATE_READ: | | 995 | case EC_STATE_READ: |
824 | if ((reg & EC_STATUS_IBF) != 0) | | 996 | if ((reg & EC_STATUS_IBF) != 0) |
825 | break; /* Nothing of interest here. */ | | 997 | break; /* Nothing of interest here. */ |
826 | | | | |
827 | acpiec_write_command(sc, EC_COMMAND_READ); | | 998 | acpiec_write_command(sc, EC_COMMAND_READ); |
828 | sc->sc_state = EC_STATE_READ_ADDR; | | 999 | sc->sc_state = EC_STATE_READ_ADDR; |
829 | break; | | 1000 | break; |
830 | | | 1001 | |
831 | case EC_STATE_READ_ADDR: | | 1002 | case EC_STATE_READ_ADDR: |
832 | if ((reg & EC_STATUS_IBF) != 0) | | 1003 | if ((reg & EC_STATUS_IBF) != 0) |
833 | break; /* Nothing of interest here. */ | | 1004 | break; /* Nothing of interest here. */ |
834 | | | | |
835 | acpiec_write_data(sc, sc->sc_cur_addr); | | 1005 | acpiec_write_data(sc, sc->sc_cur_addr); |
836 | sc->sc_state = EC_STATE_READ_VAL; | | 1006 | sc->sc_state = EC_STATE_READ_VAL; |
837 | break; | | 1007 | break; |
838 | | | 1008 | |
839 | case EC_STATE_READ_VAL: | | 1009 | case EC_STATE_READ_VAL: |
840 | if ((reg & EC_STATUS_OBF) == 0) | | 1010 | if ((reg & EC_STATUS_OBF) == 0) |
841 | break; /* Nothing of interest here. */ | | 1011 | break; /* Nothing of interest here. */ |
842 | sc->sc_cur_val = acpiec_read_data(sc); | | 1012 | sc->sc_cur_val = acpiec_read_data(sc); |
843 | sc->sc_state = EC_STATE_FREE; | | 1013 | sc->sc_state = EC_STATE_FREE; |
844 | | | | |
845 | cv_signal(&sc->sc_cv); | | | |
846 | break; | | 1014 | break; |
847 | | | 1015 | |
848 | case EC_STATE_WRITE: | | 1016 | case EC_STATE_WRITE: |
849 | if ((reg & EC_STATUS_IBF) != 0) | | 1017 | if ((reg & EC_STATUS_IBF) != 0) |
850 | break; /* Nothing of interest here. */ | | 1018 | break; /* Nothing of interest here. */ |
851 | | | | |
852 | acpiec_write_command(sc, EC_COMMAND_WRITE); | | 1019 | acpiec_write_command(sc, EC_COMMAND_WRITE); |
853 | sc->sc_state = EC_STATE_WRITE_ADDR; | | 1020 | sc->sc_state = EC_STATE_WRITE_ADDR; |
854 | break; | | 1021 | break; |
855 | | | 1022 | |
856 | case EC_STATE_WRITE_ADDR: | | 1023 | case EC_STATE_WRITE_ADDR: |
857 | if ((reg & EC_STATUS_IBF) != 0) | | 1024 | if ((reg & EC_STATUS_IBF) != 0) |
858 | break; /* Nothing of interest here. */ | | 1025 | break; /* Nothing of interest here. */ |
859 | acpiec_write_data(sc, sc->sc_cur_addr); | | 1026 | acpiec_write_data(sc, sc->sc_cur_addr); |
860 | sc->sc_state = EC_STATE_WRITE_VAL; | | 1027 | sc->sc_state = EC_STATE_WRITE_VAL; |
861 | break; | | 1028 | break; |
862 | | | 1029 | |
863 | case EC_STATE_WRITE_VAL: | | 1030 | case EC_STATE_WRITE_VAL: |
864 | if ((reg & EC_STATUS_IBF) != 0) | | 1031 | if ((reg & EC_STATUS_IBF) != 0) |
865 | break; /* Nothing of interest here. */ | | 1032 | break; /* Nothing of interest here. */ |
866 | sc->sc_state = EC_STATE_FREE; | | | |
867 | cv_signal(&sc->sc_cv); | | | |
868 | | | | |
869 | acpiec_write_data(sc, sc->sc_cur_val); | | 1033 | acpiec_write_data(sc, sc->sc_cur_val); |
| | | 1034 | sc->sc_state = EC_STATE_FREE; |
870 | break; | | 1035 | break; |
871 | | | 1036 | |
872 | case EC_STATE_FREE: | | 1037 | case EC_STATE_FREE: |
873 | if (sc->sc_got_sci) | | | |
874 | cv_signal(&sc->sc_cv_sci); | | | |
875 | break; | | 1038 | break; |
| | | 1039 | |
876 | default: | | 1040 | default: |
877 | panic("invalid state"); | | 1041 | panic("invalid state"); |
878 | } | | 1042 | } |
879 | | | 1043 | |
880 | if (sc->sc_state != EC_STATE_FREE) | | 1044 | /* |
| | | 1045 | * If we are not in a transaction, wake anyone waiting to start |
| | | 1046 | * one. If an SCI was requested, notify the SCI thread that it |
| | | 1047 | * needs to handle the SCI. |
| | | 1048 | */ |
| | | 1049 | if (sc->sc_state == EC_STATE_FREE) { |
| | | 1050 | cv_signal(&sc->sc_cv); |
| | | 1051 | if (reg & EC_STATUS_SCI) { |
| | | 1052 | DPRINTF(ACPIEC_DEBUG_TRANSITION, sc, |
| | | 1053 | "wake SCI thread\n"); |
| | | 1054 | sc->sc_got_sci = true; |
| | | 1055 | cv_signal(&sc->sc_cv_sci); |
| | | 1056 | } |
| | | 1057 | } |
| | | 1058 | |
| | | 1059 | /* |
| | | 1060 | * In case GPE interrupts are broken, poll once per tick for EC |
| | | 1061 | * status updates while a transaction is still pending. |
| | | 1062 | */ |
| | | 1063 | if (sc->sc_state != EC_STATE_FREE) { |
| | | 1064 | DPRINTF(ACPIEC_DEBUG_INTR, sc, "schedule callout\n"); |
881 | callout_schedule(&sc->sc_pseudo_intr, 1); | | 1065 | callout_schedule(&sc->sc_pseudo_intr, 1); |
| | | 1066 | } |
| | | 1067 | |
| | | 1068 | DPRINTF(ACPIEC_DEBUG_TRANSITION, sc, "return\n"); |
882 | } | | 1069 | } |
883 | | | 1070 | |
884 | static void | | 1071 | static void |
885 | acpiec_callout(void *arg) | | 1072 | acpiec_callout(void *arg) |
886 | { | | 1073 | { |
887 | device_t dv = arg; | | 1074 | struct acpiec_softc *sc = arg; |
888 | struct acpiec_softc *sc = device_private(dv); | | | |
889 | | | 1075 | |
890 | mutex_enter(&sc->sc_mtx); | | 1076 | mutex_enter(&sc->sc_mtx); |
891 | acpiec_gpe_state_machine(dv); | | 1077 | DPRINTF(ACPIEC_DEBUG_INTR, sc, "callout\n"); |
| | | 1078 | acpiec_gpe_state_machine(sc); |
892 | mutex_exit(&sc->sc_mtx); | | 1079 | mutex_exit(&sc->sc_mtx); |
893 | } | | 1080 | } |
894 | | | 1081 | |
895 | static uint32_t | | 1082 | static uint32_t |
896 | acpiec_gpe_handler(ACPI_HANDLE hdl, uint32_t gpebit, void *arg) | | 1083 | acpiec_gpe_handler(ACPI_HANDLE hdl, uint32_t gpebit, void *arg) |
897 | { | | 1084 | { |
898 | device_t dv = arg; | | 1085 | struct acpiec_softc *sc = arg; |
899 | struct acpiec_softc *sc = device_private(dv); | | | |
900 | | | 1086 | |
901 | mutex_enter(&sc->sc_mtx); | | 1087 | mutex_enter(&sc->sc_mtx); |
902 | acpiec_gpe_state_machine(dv); | | 1088 | DPRINTF(ACPIEC_DEBUG_INTR, sc, "GPE\n"); |
| | | 1089 | acpiec_gpe_state_machine(sc); |
903 | mutex_exit(&sc->sc_mtx); | | 1090 | mutex_exit(&sc->sc_mtx); |
904 | | | 1091 | |
905 | return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; | | 1092 | return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE; |
906 | } | | 1093 | } |
907 | | | 1094 | |
908 | ACPI_STATUS | | 1095 | ACPI_STATUS |
909 | acpiec_bus_read(device_t dv, u_int addr, ACPI_INTEGER *val, int width) | | 1096 | acpiec_bus_read(device_t dv, u_int addr, ACPI_INTEGER *val, int width) |
910 | { | | 1097 | { |
911 | return acpiec_space_handler(ACPI_READ, addr, width * 8, val, dv, NULL); | | 1098 | struct acpiec_softc *sc = device_private(dv); |
| | | 1099 | |
| | | 1100 | return acpiec_space_handler(ACPI_READ, addr, width * 8, val, sc, NULL); |
912 | } | | 1101 | } |
913 | | | 1102 | |
914 | ACPI_STATUS | | 1103 | ACPI_STATUS |
915 | acpiec_bus_write(device_t dv, u_int addr, ACPI_INTEGER val, int width) | | 1104 | acpiec_bus_write(device_t dv, u_int addr, ACPI_INTEGER val, int width) |
916 | { | | 1105 | { |
917 | return acpiec_space_handler(ACPI_WRITE, addr, width * 8, &val, dv, | | 1106 | struct acpiec_softc *sc = device_private(dv); |
| | | 1107 | |
| | | 1108 | return acpiec_space_handler(ACPI_WRITE, addr, width * 8, &val, sc, |
918 | NULL); | | 1109 | NULL); |
919 | } | | 1110 | } |
920 | | | 1111 | |
921 | ACPI_HANDLE | | 1112 | ACPI_HANDLE |
922 | acpiec_get_handle(device_t dv) | | 1113 | acpiec_get_handle(device_t dv) |
923 | { | | 1114 | { |
924 | struct acpiec_softc *sc = device_private(dv); | | 1115 | struct acpiec_softc *sc = device_private(dv); |
925 | | | 1116 | |
926 | return sc->sc_ech; | | 1117 | return sc->sc_ech; |
927 | } | | 1118 | } |