Re: HiFive Unmatched clean poweroff using the power button
> From: Jeremie Courreges-Anglas > Date: Sat, 01 Oct 2022 18:36:35 +0200 > > On Thu, Aug 18 2022, Jeremie Courreges-Anglas wrote: > > Some time ago I wanted to get a clean poweroff from the power button on > > my Unmatched, so that I don't get fsck at reboot the morning after > > someone sleeps in the room where the machine lives. kettenis kindly > > provided sfgpio(4) to get interrupts working on dapmic(4) instead of my > > initial hack that used polling. > > > > One issue I struggled with for a bit is that masking irqs also masks the > > wake-up events, particularly the events we use for dapmic_reset(). > > With the diff below most interrupt events are masked off during runtime, > > until we're shutting down/rebooting. Maybe this is too paranoid and > > I should let more events go through the intr handler, eg for wake-up > > events that I don't envision yet? (I would love to get wake on lan > > support in cad(4) but my attempts led nowhere so far.) > > > > Also interesting, the fault register needs to be cleared at boot, else > > the interrupt will keep triggering after eg a hard button-driven poweroff. > > We could log the faults found in FAULT_LOG at boot time to know why the > > machine has stopped. But I'm more concerned about what to do if we get > > a fault at runtime (see the XXX). When I tried to disestablish the > > interrupt handler with fdt_intr_disestablish(sc->sc_ih) from > > dapmic_reset(), I got a fault. Maybe something worth investigating. > > The FAULT_LOG register handling seems appropriate after reading entry > 6.2 in: > > > https://www.renesas.com/eu/en/document/apn/shared-irq-line-considerations-pm-059 > > I wish I had read this document earlier. :) > > > The code below is based off da9063_datasheet_2v2.pdf. I don't know of > > other machines we run on that use this controller, the only entry in > > dmesglog is matthieu's Unmatched machine. > > > > Tests, input and oks welcome. > > In the case where my hifive unmatched lives, I have wired both the > shutdown and the reset buttons. Yesterday I tried to see whether the > reset button could be handled as a clean reboot, but looking at the > hifive unmatched board schematics it seems that the PMIC has no control > over it (even if tweaking nRES_MODE). So the diff stands for scrutiny. > I would like input and maybe oks to get this in. ;) Finally managed to get this tested. It works for my chassis as well! A few nits below. With those fixed, ok kettenis@ > Index: dev/fdt/dapmic.c > === > RCS file: /cvs/src/sys/dev/fdt/dapmic.c,v > retrieving revision 1.2 > diff -u -p -r1.2 dapmic.c > --- dev/fdt/dapmic.c 6 Apr 2022 18:59:28 - 1.2 > +++ dev/fdt/dapmic.c 17 Aug 2022 21:59:57 - > @@ -19,6 +19,9 @@ > #include > #include > #include > +#include > +#include > +#include > > #include > #include > @@ -28,11 +31,31 @@ > > #include > > +#include > + > extern void (*cpuresetfn)(void); > extern void (*powerdownfn)(void); > > /* Registers */ > +#define FAULT_LOG0x05 > #define EVENT_A 0x06 > +#define EVENT_A_EVENTS_D(1 << 7) > +#define EVENT_A_EVENTS_C(1 << 6) > +#define EVENT_A_EVENTS_B(1 << 5) > +#define EVENT_A_E_nONKEY(1 << 0) > +#define EVENT_B 0x07 > +#define EVENT_C 0x08 > +#define EVENT_D 0x09 > +#define IRQ_MASK_A 0x0a > +#define IRQ_MASK_A_M_RESERVED ((1 << 7) | (1 << 6) | (1 << 5)) > +#define IRQ_MASK_A_M_SEQ_RDY(1 << 4) > +#define IRQ_MASK_A_M_ADC_RDY(1 << 3) > +#define IRQ_MASK_A_M_TICK (1 << 2) > +#define IRQ_MASK_A_M_ALARM (1 << 1) > +#define IRQ_MASK_A_M_nONKEY (1 << 0) > +#define IRQ_MASK_B 0x0b > +#define IRQ_MASK_C 0x0c > +#define IRQ_MASK_D 0x0d > #define CONTROL_F0x13 > #define CONTROL_F_WAKE_UP (1 << 2) > #define CONTROL_F_SHUTDOWN (1 << 1) > @@ -55,11 +78,20 @@ extern void (*powerdownfn)(void); > #define ALARM_Y 0x4b > #define ALARM_Y_TICK_ON (1 << 7) > > +#ifdef DAPMIC_DEBUG > +# define DPRINTF(args) do { printf args; } while (0) > +#else > +# define DPRINTF(args) do {} while (0) > +#endif > + > struct dapmic_softc { > struct device sc_dev; > i2c_tag_t sc_tag; > i2c_addr_t sc_addr; > > + int (*sc_ih)(void *); > + struct task sc_task; > + > struct todr_chip_handle sc_todr; > }; > > @@ -80,8 +112,11 @@ int dapmic_clock_read(struct dapmic_soft > int dapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *); > int dapmic_gettime(struct todr_chip_handle *, struct timeval *); > int dapmic_settime(struct todr_chip_handle *, struct timeval *); > +void dapmic_reset_irq_mask(struct dapmic_softc *); > void
Re: HiFive Unmatched clean poweroff using the power button
On Thu, Aug 18 2022, Jeremie Courreges-Anglas wrote: > Some time ago I wanted to get a clean poweroff from the power button on > my Unmatched, so that I don't get fsck at reboot the morning after > someone sleeps in the room where the machine lives. kettenis kindly > provided sfgpio(4) to get interrupts working on dapmic(4) instead of my > initial hack that used polling. > > One issue I struggled with for a bit is that masking irqs also masks the > wake-up events, particularly the events we use for dapmic_reset(). > With the diff below most interrupt events are masked off during runtime, > until we're shutting down/rebooting. Maybe this is too paranoid and > I should let more events go through the intr handler, eg for wake-up > events that I don't envision yet? (I would love to get wake on lan > support in cad(4) but my attempts led nowhere so far.) > > Also interesting, the fault register needs to be cleared at boot, else > the interrupt will keep triggering after eg a hard button-driven poweroff. > We could log the faults found in FAULT_LOG at boot time to know why the > machine has stopped. But I'm more concerned about what to do if we get > a fault at runtime (see the XXX). When I tried to disestablish the > interrupt handler with fdt_intr_disestablish(sc->sc_ih) from > dapmic_reset(), I got a fault. Maybe something worth investigating. The FAULT_LOG register handling seems appropriate after reading entry 6.2 in: https://www.renesas.com/eu/en/document/apn/shared-irq-line-considerations-pm-059 I wish I had read this document earlier. :) > The code below is based off da9063_datasheet_2v2.pdf. I don't know of > other machines we run on that use this controller, the only entry in > dmesglog is matthieu's Unmatched machine. > > Tests, input and oks welcome. In the case where my hifive unmatched lives, I have wired both the shutdown and the reset buttons. Yesterday I tried to see whether the reset button could be handled as a clean reboot, but looking at the hifive unmatched board schematics it seems that the PMIC has no control over it (even if tweaking nRES_MODE). So the diff stands for scrutiny. I would like input and maybe oks to get this in. ;) Index: dev/fdt/dapmic.c === RCS file: /cvs/src/sys/dev/fdt/dapmic.c,v retrieving revision 1.2 diff -u -p -r1.2 dapmic.c --- dev/fdt/dapmic.c6 Apr 2022 18:59:28 - 1.2 +++ dev/fdt/dapmic.c17 Aug 2022 21:59:57 - @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include @@ -28,11 +31,31 @@ #include +#include + extern void (*cpuresetfn)(void); extern void (*powerdownfn)(void); /* Registers */ +#define FAULT_LOG 0x05 #define EVENT_A0x06 +#define EVENT_A_EVENTS_D (1 << 7) +#define EVENT_A_EVENTS_C (1 << 6) +#define EVENT_A_EVENTS_B (1 << 5) +#define EVENT_A_E_nONKEY (1 << 0) +#define EVENT_B0x07 +#define EVENT_C0x08 +#define EVENT_D0x09 +#define IRQ_MASK_A 0x0a +#define IRQ_MASK_A_M_RESERVED ((1 << 7) | (1 << 6) | (1 << 5)) +#define IRQ_MASK_A_M_SEQ_RDY (1 << 4) +#define IRQ_MASK_A_M_ADC_RDY (1 << 3) +#define IRQ_MASK_A_M_TICK (1 << 2) +#define IRQ_MASK_A_M_ALARM(1 << 1) +#define IRQ_MASK_A_M_nONKEY (1 << 0) +#define IRQ_MASK_B 0x0b +#define IRQ_MASK_C 0x0c +#define IRQ_MASK_D 0x0d #define CONTROL_F 0x13 #define CONTROL_F_WAKE_UP (1 << 2) #define CONTROL_F_SHUTDOWN(1 << 1) @@ -55,11 +78,20 @@ extern void (*powerdownfn)(void); #define ALARM_Y0x4b #define ALARM_Y_TICK_ON (1 << 7) +#ifdef DAPMIC_DEBUG +# define DPRINTF(args) do { printf args; } while (0) +#else +# define DPRINTF(args) do {} while (0) +#endif + struct dapmic_softc { struct device sc_dev; i2c_tag_t sc_tag; i2c_addr_t sc_addr; + int (*sc_ih)(void *); + struct task sc_task; + struct todr_chip_handle sc_todr; }; @@ -80,8 +112,11 @@ int dapmic_clock_read(struct dapmic_soft intdapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *); intdapmic_gettime(struct todr_chip_handle *, struct timeval *); intdapmic_settime(struct todr_chip_handle *, struct timeval *); +void dapmic_reset_irq_mask(struct dapmic_softc *); void dapmic_reset(void); void dapmic_powerdown(void); +intdapmic_intr(void *); +void dapmic_shutdown_task(void *); int dapmic_match(struct device *parent, void *match, void *aux) @@ -96,6 +131,7 @@ dapmic_attach(struct device *parent, str { struct dapmic_softc *sc = (struct dapmic_softc *)self; struct i2c_attach_args *ia = aux; + int node = *(int *)ia->ia_cookie;
HiFive Unmatched clean poweroff using the power button
Some time ago I wanted to get a clean poweroff from the power button on my Unmatched, so that I don't get fsck at reboot the morning after someone sleeps in the room where the machine lives. kettenis kindly provided sfgpio(4) to get interrupts working on dapmic(4) instead of my initial hack that used polling. One issue I struggled with for a bit is that masking irqs also masks the wake-up events, particularly the events we use for dapmic_reset(). With the diff below most interrupt events are masked off during runtime, until we're shutting down/rebooting. Maybe this is too paranoid and I should let more events go through the intr handler, eg for wake-up events that I don't envision yet? (I would love to get wake on lan support in cad(4) but my attempts led nowhere so far.) Also interesting, the fault register needs to be cleared at boot, else the interrupt will keep triggering after eg a hard button-driven poweroff. We could log the faults found in FAULT_LOG at boot time to know why the machine has stopped. But I'm more concerned about what to do if we get a fault at runtime (see the XXX). When I tried to disestablish the interrupt handler with fdt_intr_disestablish(sc->sc_ih) from dapmic_reset(), I got a fault. Maybe something worth investigating. The code below is based off da9063_datasheet_2v2.pdf. I don't know of other machines we run on that use this controller, the only entry in dmesglog is matthieu's Unmatched machine. Tests, input and oks welcome. Index: dev/fdt/dapmic.c === RCS file: /cvs/src/sys/dev/fdt/dapmic.c,v retrieving revision 1.2 diff -u -p -r1.2 dapmic.c --- dev/fdt/dapmic.c6 Apr 2022 18:59:28 - 1.2 +++ dev/fdt/dapmic.c17 Aug 2022 21:59:57 - @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include @@ -28,11 +31,31 @@ #include +#include + extern void (*cpuresetfn)(void); extern void (*powerdownfn)(void); /* Registers */ +#define FAULT_LOG 0x05 #define EVENT_A0x06 +#define EVENT_A_EVENTS_D (1 << 7) +#define EVENT_A_EVENTS_C (1 << 6) +#define EVENT_A_EVENTS_B (1 << 5) +#define EVENT_A_E_nONKEY (1 << 0) +#define EVENT_B0x07 +#define EVENT_C0x08 +#define EVENT_D0x09 +#define IRQ_MASK_A 0x0a +#define IRQ_MASK_A_M_RESERVED ((1 << 7) | (1 << 6) | (1 << 5)) +#define IRQ_MASK_A_M_SEQ_RDY (1 << 4) +#define IRQ_MASK_A_M_ADC_RDY (1 << 3) +#define IRQ_MASK_A_M_TICK (1 << 2) +#define IRQ_MASK_A_M_ALARM(1 << 1) +#define IRQ_MASK_A_M_nONKEY (1 << 0) +#define IRQ_MASK_B 0x0b +#define IRQ_MASK_C 0x0c +#define IRQ_MASK_D 0x0d #define CONTROL_F 0x13 #define CONTROL_F_WAKE_UP (1 << 2) #define CONTROL_F_SHUTDOWN(1 << 1) @@ -55,11 +78,20 @@ extern void (*powerdownfn)(void); #define ALARM_Y0x4b #define ALARM_Y_TICK_ON (1 << 7) +#ifdef DAPMIC_DEBUG +# define DPRINTF(args) do { printf args; } while (0) +#else +# define DPRINTF(args) do {} while (0) +#endif + struct dapmic_softc { struct device sc_dev; i2c_tag_t sc_tag; i2c_addr_t sc_addr; + int (*sc_ih)(void *); + struct task sc_task; + struct todr_chip_handle sc_todr; }; @@ -80,8 +112,11 @@ int dapmic_clock_read(struct dapmic_soft intdapmic_clock_write(struct dapmic_softc *, struct clock_ymdhms *); intdapmic_gettime(struct todr_chip_handle *, struct timeval *); intdapmic_settime(struct todr_chip_handle *, struct timeval *); +void dapmic_reset_irq_mask(struct dapmic_softc *); void dapmic_reset(void); void dapmic_powerdown(void); +intdapmic_intr(void *); +void dapmic_shutdown_task(void *); int dapmic_match(struct device *parent, void *match, void *aux) @@ -96,6 +131,7 @@ dapmic_attach(struct device *parent, str { struct dapmic_softc *sc = (struct dapmic_softc *)self; struct i2c_attach_args *ia = aux; + int node = *(int *)ia->ia_cookie; sc->sc_tag = ia->ia_tag; sc->sc_addr = ia->ia_addr; @@ -105,12 +141,35 @@ dapmic_attach(struct device *parent, str sc->sc_todr.todr_settime = dapmic_settime; todr_attach(>sc_todr); - printf("\n"); - if (cpuresetfn == NULL) cpuresetfn = dapmic_reset; if (powerdownfn == NULL) powerdownfn = dapmic_powerdown; + + task_set(>sc_task, dapmic_shutdown_task, sc); + + /* Mask away events we don't care about */ + dapmic_reg_write(sc, IRQ_MASK_A, + 0xff & ~(IRQ_MASK_A_M_RESERVED | IRQ_MASK_A_M_nONKEY)); + dapmic_reg_write(sc, IRQ_MASK_B, 0xff); + dapmic_reg_write(sc, IRQ_MASK_C, 0xff); +