> Date: Wed, 15 Sep 2021 17:29:39 +0200 (CEST) > From: Mark Kettenis <mark.kette...@xs4all.nl> > > The diff below is a preliminary diff to fix a suspend/resume issue on > recent Thinkpads. This needs testing on a wider range of laptops to > make sure it doesn't break things. The diff also puts some > information in dmesg that will help me improve things in the future. > > So, if you have a laptop where pchgpio(4) attaches *and* supports S3 > suspen/resume, please apply this diff, do a suspend/resume cycle and > send me a dmesg collected after that suspend/resume cycle.
This diff is now in snapshots, so instead of applying the diff and build your own kernel, you can just upgrade to the latest snapshot. Thanks, Mark > Index: dev/acpi/pchgpio.c > =================================================================== > RCS file: /cvs/src/sys/dev/acpi/pchgpio.c,v > retrieving revision 1.5 > diff -u -p -r1.5 pchgpio.c > --- dev/acpi/pchgpio.c 30 Aug 2021 18:40:19 -0000 1.5 > +++ dev/acpi/pchgpio.c 15 Sep 2021 15:16:52 -0000 > @@ -28,12 +28,13 @@ > > #define PCHGPIO_MAXCOM 4 > > -#define PCHGPIO_CONF_TXSTATE 0x00000001 > -#define PCHGPIO_CONF_RXSTATE 0x00000002 > -#define PCHGPIO_CONF_RXINV 0x00800000 > -#define PCHGPIO_CONF_RXEV_EDGE 0x02000000 > -#define PCHGPIO_CONF_RXEV_ZERO 0x04000000 > -#define PCHGPIO_CONF_RXEV_MASK 0x06000000 > +#define PCHGPIO_CONF_TXSTATE 0x00000001 > +#define PCHGPIO_CONF_RXSTATE 0x00000002 > +#define PCHGPIO_CONF_RXINV 0x00800000 > +#define PCHGPIO_CONF_RXEV_EDGE 0x02000000 > +#define PCHGPIO_CONF_RXEV_ZERO 0x04000000 > +#define PCHGPIO_CONF_RXEV_MASK 0x06000000 > +#define PCHGPIO_CONF_PADRSTCFG_MASK 0xc0000000 > > #define PCHGPIO_PADBAR 0x00c > > @@ -59,6 +60,11 @@ struct pchgpio_match { > const struct pchgpio_device *device; > }; > > +struct pchgpio_pincfg { > + uint32_t pad_cfg_dw0; > + uint32_t pad_cfg_dw1; > +}; > + > struct pchgpio_intrhand { > int (*ih_func)(void *); > void *ih_arg; > @@ -80,6 +86,7 @@ struct pchgpio_softc { > int sc_padsize; > > int sc_npins; > + struct pchgpio_pincfg *sc_pin_cfg; > struct pchgpio_intrhand *sc_pin_ih; > > struct acpi_gpio sc_gpio; > @@ -87,9 +94,11 @@ struct pchgpio_softc { > > int pchgpio_match(struct device *, void *, void *); > void pchgpio_attach(struct device *, struct device *, void *); > +int pchgpio_activate(struct device *, int); > > struct cfattach pchgpio_ca = { > - sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach > + sizeof(struct pchgpio_softc), pchgpio_match, pchgpio_attach, > + NULL, pchgpio_activate > }; > > struct cfdriver pchgpio_cd = { > @@ -170,6 +179,8 @@ int pchgpio_read_pin(void *, int); > void pchgpio_write_pin(void *, int, int); > void pchgpio_intr_establish(void *, int, int, int (*)(void *), void *); > int pchgpio_intr(void *); > +void pchgpio_save(struct pchgpio_softc *); > +void pchgpio_restore(struct pchgpio_softc *); > > int > pchgpio_match(struct device *parent, void *match, void *aux) > @@ -240,6 +251,8 @@ pchgpio_attach(struct device *parent, st > > sc->sc_padsize = sc->sc_device->pad_size; > sc->sc_npins = sc->sc_device->npins; > + sc->sc_pin_cfg = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_cfg), > + M_DEVBUF, M_WAITOK); > sc->sc_pin_ih = mallocarray(sc->sc_npins, sizeof(*sc->sc_pin_ih), > M_DEVBUF, M_WAITOK | M_ZERO); > > @@ -263,11 +276,48 @@ pchgpio_attach(struct device *parent, st > > unmap: > free(sc->sc_pin_ih, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_ih)); > + free(sc->sc_pin_cfg, M_DEVBUF, sc->sc_npins * sizeof(*sc->sc_pin_cfg)); > for (i = 0; i < sc->sc_naddr; i++) > bus_space_unmap(sc->sc_memt[i], sc->sc_memh[i], > aaa->aaa_size[i]); > } > > +int > +pchgpio_activate(struct device *self, int act) > +{ > + struct pchgpio_softc *sc = (struct pchgpio_softc *)self; > +// int i, j; > + > + switch (act) { > + case DVACT_SUSPEND: > + printf("%s: suspend\n", sc->sc_dev.dv_xname); > +#if 0 > + for (i = 0; i < 4; i++) { > + for (j = 0; j < 0xc00; j += 4) { > + printf("%04x: 0x%08x\n", j, > + bus_space_read_4(sc->sc_memt[i], > sc->sc_memh[i], j)); > + } > + } > +#endif > + pchgpio_save(sc); > + break; > + case DVACT_RESUME: > + printf("%s: resume\n", sc->sc_dev.dv_xname); > +#if 0 > + for (i = 0; i < 4; i++) { > + for (j = 0; j < 0xc00; j += 4) { > + printf("%04x: 0x%08x\n", j, > + bus_space_read_4(sc->sc_memt[i], > sc->sc_memh[i], j)); > + } > + } > +#endif > + pchgpio_restore(sc); > + break; > + } > + > + return 0; > +} > + > const struct pchgpio_group * > pchgpio_find_group(struct pchgpio_softc *sc, int pin) > { > @@ -403,4 +453,74 @@ pchgpio_intr(void *arg) > } > > return handled; > +} > + > +void > +pchgpio_save(struct pchgpio_softc *sc) > +{ > + int gpiobase, group, bit, pin, pad; > + uint16_t base, limit; > + uint8_t bank, bar; > + > + for (group = 0; group < sc->sc_device->ngroups; group++) { > + bar = sc->sc_device->groups[group].bar; > + bank = sc->sc_device->groups[group].bank; > + base = sc->sc_device->groups[group].base; > + limit = sc->sc_device->groups[group].limit; > + gpiobase = sc->sc_device->groups[group].gpiobase; > + > + for (bit = 0; bit <= (limit - base); bit++) { > + pin = gpiobase + bit; > + pad = base + bit - sc->sc_padbase[bar]; > + > + sc->sc_pin_cfg[pin].pad_cfg_dw0 = > + bus_space_read_4(sc->sc_memt[bar], > + sc->sc_memh[bar], > + sc->sc_padbar[bar] + pad * sc->sc_padsize); > + sc->sc_pin_cfg[pin].pad_cfg_dw1 = > + bus_space_read_4(sc->sc_memt[bar], > + sc->sc_memh[bar], > + sc->sc_padbar[bar] + pad * sc->sc_padsize + 4); > + } > + } > +} > + > +void > +pchgpio_restore(struct pchgpio_softc *sc) > +{ > + int gpiobase, group, bit, pin, pad; > + uint32_t pad_cfg_dw0, pad_cfg_dw1; > + uint16_t base, limit; > + uint8_t bank, bar; > + > + for (group = 0; group < sc->sc_device->ngroups; group++) { > + bar = sc->sc_device->groups[group].bar; > + bank = sc->sc_device->groups[group].bank; > + base = sc->sc_device->groups[group].base; > + limit = sc->sc_device->groups[group].limit; > + gpiobase = sc->sc_device->groups[group].gpiobase; > + > + for (bit = 0; bit <= (limit - base); bit++) { > + pin = gpiobase + bit; > + pad = base + bit - sc->sc_padbase[bar]; > + > + pad_cfg_dw0 = bus_space_read_4(sc->sc_memt[bar], > + sc->sc_memh[bar], sc->sc_padbar[bar] + pad * > sc->sc_padsize); > + pad_cfg_dw1 = bus_space_read_4(sc->sc_memt[bar], > + sc->sc_memh[bar], sc->sc_padbar[bar] + pad * > sc->sc_padsize + 4); > + if (pad_cfg_dw0 != sc->sc_pin_cfg[pin].pad_cfg_dw0) > + printf("bar %d bank %d bit %d pad %d: dw0 > 0x%08x -> 0x%08x\n", bar, bank, bit, pad, sc->sc_pin_cfg[pin].pad_cfg_dw0, > pad_cfg_dw0); > + if (pad_cfg_dw1 != sc->sc_pin_cfg[pin].pad_cfg_dw1) > + printf("bar %d bank %d bit %d pad %d: dw1 > 0x%08x -> 0x%08x\n", bar, bank, bit, pad, sc->sc_pin_cfg[pin].pad_cfg_dw1, > pad_cfg_dw1); > + > + /* XXX */ > + if ((sc->sc_pin_cfg[pin].pad_cfg_dw0 & > PCHGPIO_CONF_PADRSTCFG_MASK) != > + (pad_cfg_dw0 & PCHGPIO_CONF_PADRSTCFG_MASK)) { > + bus_space_write_4(sc->sc_memt[bar], > + sc->sc_memh[bar], > + sc->sc_padbar[bar] + pad * sc->sc_padsize, > + sc->sc_pin_cfg[pin].pad_cfg_dw0); > + } > + } > + } > } > >