Source-Changes-D archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: CVS commit: src/sys/dev/i2c
Hi,
"Jason R Thorpe" <thorpej%netbsd.org@localhost> writes:
> Module Name: src
> Committed By: thorpej
> Date: Sun Dec 22 16:44:35 UTC 2019
>
> Modified Files:
> src/sys/dev/i2c: ihidev.c ihidev.h
>
> Log Message:
> The hid-over-i2c spec specifies that compliant devices use level-sensitive
> interrupts. However, it's not safe to do i2c bus access in hard interrupt
> context, and we must read the event data off the device in order to clear
> the interrupt condition.
>
> Address this by using acpi_intr_mask() to mask off the interrupt source
> while a softint is pending to service the events, re-enabling it once
> servicing is completed.
>
> While here, re-factor the interrupt setup / tear-down code a bit to
> eventually once day simplify supporting the FDT bindings for hid-over-i2c.
This change freezes an amd64 kernel boot on my laptop.
And I cannot enter into DDB with ALt+Ctrl+ESC.
My laptop is HP Spectre x360 and it has twi ims(4) touch/pen screen.
With "userconf disable ihidev", the kernel boots fine as of
2019-12-24T08:00 (UTC).
Could you take a look at my problem?
> To generate a diff of this commit:
> cvs rdiff -u -r1.9 -r1.10 src/sys/dev/i2c/ihidev.c
> cvs rdiff -u -r1.1 -r1.2 src/sys/dev/i2c/ihidev.h
>
> Please note that diffs are not public domain; they are subject to the
> copyright notices on the relevant files.
>
> Modified files:
>
> Index: src/sys/dev/i2c/ihidev.c
> diff -u src/sys/dev/i2c/ihidev.c:1.9 src/sys/dev/i2c/ihidev.c:1.10
> --- src/sys/dev/i2c/ihidev.c:1.9 Tue Oct 1 18:00:08 2019
> +++ src/sys/dev/i2c/ihidev.c Sun Dec 22 16:44:35 2019
> @@ -1,4 +1,4 @@
> -/* $NetBSD: ihidev.c,v 1.9 2019/10/01 18:00:08 chs Exp $ */
> +/* $NetBSD: ihidev.c,v 1.10 2019/12/22 16:44:35 thorpej Exp $ */
> /* $OpenBSD ihidev.c,v 1.13 2017/04/08 02:57:23 deraadt Exp $ */
>
> /*-
> @@ -54,7 +54,7 @@
> */
>
> #include <sys/cdefs.h>
> -__KERNEL_RCSID(0, "$NetBSD: ihidev.c,v 1.9 2019/10/01 18:00:08 chs Exp $");
> +__KERNEL_RCSID(0, "$NetBSD: ihidev.c,v 1.10 2019/12/22 16:44:35 thorpej Exp $");
>
> #include <sys/param.h>
> #include <sys/systm.h>
> @@ -71,6 +71,7 @@ __KERNEL_RCSID(0, "$NetBSD: ihidev.c,v 1
> # include "acpica.h"
> #endif
> #if NACPICA > 0
> +#include <dev/acpi/acpivar.h>
> #include <dev/acpi/acpi_intr.h>
> #endif
>
> @@ -109,10 +110,14 @@ static int ihidev_detach(device_t, int);
> CFATTACH_DECL_NEW(ihidev, sizeof(struct ihidev_softc),
> ihidev_match, ihidev_attach, ihidev_detach, NULL);
>
> +static bool ihiddev_intr_init(struct ihidev_softc *);
> +static void ihiddev_intr_fini(struct ihidev_softc *);
> +
> static bool ihidev_suspend(device_t, const pmf_qual_t *);
> static bool ihidev_resume(device_t, const pmf_qual_t *);
> static int ihidev_hid_command(struct ihidev_softc *, int, void *, bool);
> static int ihidev_intr(void *);
> +static void ihidev_softintr(void *);
> static int ihidev_reset(struct ihidev_softc *, bool);
> static int ihidev_hid_desc_parse(struct ihidev_softc *);
>
> @@ -200,20 +205,9 @@ ihidev_attach(device_t parent, device_t
> repsz));
> }
> sc->sc_ibuf = kmem_zalloc(sc->sc_isize, KM_SLEEP);
> -#if NACPICA > 0
> - {
> - char buf[100];
> -
> - sc->sc_ih = acpi_intr_establish(self, sc->sc_phandle, IPL_TTY,
> - false, ihidev_intr, sc, device_xname(self));
> - if (sc->sc_ih == NULL) {
> - aprint_error_dev(self, "can't establish interrupt\n");
> - return;
> - }
> - aprint_normal_dev(self, "interrupting at %s\n",
> - acpi_intr_string(sc->sc_ih, buf, sizeof(buf)));
> + if (! ihiddev_intr_init(sc)) {
> + return;
> }
> -#endif
>
> iha.iaa = ia;
> iha.parent = sc;
> @@ -260,10 +254,7 @@ ihidev_detach(device_t self, int flags)
> struct ihidev_softc *sc = device_private(self);
>
> mutex_enter(&sc->sc_intr_lock);
> -#if NACPICA > 0
> - if (sc->sc_ih != NULL)
> - acpi_intr_disestablish(sc->sc_ih);
> -#endif
> + ihiddev_intr_fini(sc);
> if (ihidev_hid_command(sc, I2C_HID_CMD_SET_POWER,
> &I2C_HID_POWER_OFF, true))
> aprint_error_dev(sc->sc_dev, "failed to power down\n");
> @@ -649,31 +640,110 @@ ihidev_hid_desc_parse(struct ihidev_soft
> return (0);
> }
>
> +static bool
> +ihiddev_intr_init(struct ihidev_softc *sc)
> +{
> +#if NACPICA > 0
> + ACPI_HANDLE hdl = (void *)(uintptr_t)sc->sc_phandle;
> + struct acpi_resources res;
> + ACPI_STATUS rv;
> + char buf[100];
> +
> + rv = acpi_resource_parse(sc->sc_dev, hdl, "_CRS", &res,
> + &acpi_resource_parse_ops_quiet);
> + if (ACPI_FAILURE(rv)) {
> + aprint_error_dev(sc->sc_dev, "can't parse '_CRS'\n");
> + return false;
> + }
> +
> + const struct acpi_irq * const irq = acpi_res_irq(&res, 0);
> + if (irq == NULL) {
> + aprint_error_dev(sc->sc_dev, "no IRQ resource\n");
> + acpi_resource_cleanup(&res);
> + return false;
> + }
> +
> + sc->sc_intr_type =
> + irq->ar_type == ACPI_EDGE_SENSITIVE ? IST_EDGE : IST_LEVEL;
> +
> + acpi_resource_cleanup(&res);
> +
> + sc->sc_ih = acpi_intr_establish(sc->sc_dev, sc->sc_phandle, IPL_TTY,
> + false, ihidev_intr, sc, device_xname(sc->sc_dev));
> + if (sc->sc_ih == NULL) {
> + aprint_error_dev(sc->sc_dev, "can't establish interrupt\n");
> + return false;
> + }
> + aprint_normal_dev(sc->sc_dev, "interrupting at %s\n",
> + acpi_intr_string(sc->sc_ih, buf, sizeof(buf)));
> +
> + sc->sc_sih = softint_establish(SOFTINT_SERIAL, ihidev_softintr, sc);
> + if (sc->sc_sih == NULL) {
> + aprint_error_dev(sc->sc_dev,
> + "can't establish soft interrupt\n");
> + return false;
> + }
> +
> + return true;
> +#else
> + aprint_error_dev(sc->sc_dev, "can't establish interrupt\n");
> + return false;
> +#endif
> +}
> +
> +static void
> +ihiddev_intr_fini(struct ihidev_softc *sc)
> +{
> +#if NACPICA > 0
> + if (sc->sc_ih != NULL) {
> + acpi_intr_disestablish(sc->sc_ih);
> + }
> + if (sc->sc_sih != NULL) {
> + softint_disestablish(sc->sc_sih);
> + }
> +#endif
> +}
> +
> static int
> ihidev_intr(void *arg)
> {
> - struct ihidev_softc *sc = arg;
> + struct ihidev_softc * const sc = arg;
> +
> + mutex_enter(&sc->sc_intr_lock);
> +
> + /*
> + * Schedule our soft interrupt handler. If we're using a level-
> + * triggered interrupt, we have to mask it off while we wait
> + * for service.
> + */
> + softint_schedule(sc->sc_sih);
> + if (sc->sc_intr_type == IST_LEVEL) {
> +#if NACPICA > 0
> + acpi_intr_mask(sc->sc_ih);
> +#endif
> + }
> +
> + mutex_exit(&sc->sc_intr_lock);
> +
> + return 1;
> +}
> +
> +static void
> +ihidev_softintr(void *arg)
> +{
> + struct ihidev_softc * const sc = arg;
> struct ihidev *scd;
> u_int psize;
> int res, i;
> u_char *p;
> u_int rep = 0;
>
> - /*
> - * XXX: force I2C_F_POLL for now to avoid dwiic interrupting
> - * while we are interrupting
> - */
> -
> - mutex_enter(&sc->sc_intr_lock);
> - iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
> -
> + iic_acquire_bus(sc->sc_tag, 0);
> res = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, NULL, 0,
> - sc->sc_ibuf, sc->sc_isize, I2C_F_POLL);
> -
> - iic_release_bus(sc->sc_tag, I2C_F_POLL);
> - mutex_exit(&sc->sc_intr_lock);
> + sc->sc_ibuf, sc->sc_isize, 0);
> + iic_release_bus(sc->sc_tag, 0);
> if (res != 0)
> - return 1;
> + goto out;
>
> /*
> * 6.1.1 - First two bytes are the packet length, which must be less
> @@ -683,7 +753,7 @@ ihidev_intr(void *arg)
> if (!psize || psize > sc->sc_isize) {
> DPRINTF(("%s: %s: invalid packet size (%d vs. %d)\n",
> sc->sc_dev.dv_xname, __func__, psize, sc->sc_isize));
> - return (1);
> + goto out;
> }
>
> /* 3rd byte is the report id */
> @@ -695,22 +765,30 @@ ihidev_intr(void *arg)
> if (rep >= sc->sc_nrepid) {
> aprint_error_dev(sc->sc_dev, "%s: bad report id %d\n",
> __func__, rep);
> - return (1);
> + goto out;
> }
>
> - DPRINTF(("%s: ihidev_intr: hid input (rep %d):", sc->sc_dev.dv_xname,
> - rep));
> + DPRINTF(("%s: %s: hid input (rep %d):", sc->sc_dev.dv_xname,
> + __func__, rep));
> for (i = 0; i < sc->sc_isize; i++)
> DPRINTF((" %.2x", sc->sc_ibuf[i]));
> DPRINTF(("\n"));
>
> scd = sc->sc_subdevs[rep];
> if (scd == NULL || !(scd->sc_state & IHIDEV_OPEN))
> - return (1);
> + goto out;
>
> scd->sc_intr(scd, p, psize);
>
> - return 1;
> + out:
> + /*
> + * If our interrupt is level-triggered, re-enable it now.
> + */
> + if (sc->sc_intr_type == IST_LEVEL) {
> +#if NACPICA > 0
> + acpi_intr_unmask(sc->sc_ih);
> +#endif
> + }
> }
>
> static int
>
> Index: src/sys/dev/i2c/ihidev.h
> diff -u src/sys/dev/i2c/ihidev.h:1.1 src/sys/dev/i2c/ihidev.h:1.2
> --- src/sys/dev/i2c/ihidev.h:1.1 Sun Dec 10 17:05:54 2017
> +++ src/sys/dev/i2c/ihidev.h Sun Dec 22 16:44:35 2019
> @@ -1,4 +1,4 @@
> -/* $NetBSD: ihidev.h,v 1.1 2017/12/10 17:05:54 bouyer Exp $ */
> +/* $NetBSD: ihidev.h,v 1.2 2019/12/22 16:44:35 thorpej Exp $ */
> /* $OpenBSD ihidev.h,v 1.4 2016/01/31 18:24:35 jcs Exp $ */
>
> /*-
> @@ -100,7 +100,9 @@ struct ihidev_softc {
> uint64_t sc_phandle;
>
> void * sc_ih;
> + void * sc_sih;
> kmutex_t sc_intr_lock;
> + int sc_intr_type;
>
> u_int sc_hid_desc_addr;
> union {
>
--
Ryo ONODERA // ryo%tetera.org@localhost
PGP fingerprint = 82A2 DC91 76E0 A10A 8ABB FD1B F404 27FA C7D1 15F3
Home |
Main Index |
Thread Index |
Old Index