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