On Sat, Feb 08, 2020 at 01:07:01PM +0800, Nathanael Rensen wrote:
> The diff below adds support for the watchdog as found in the embedded
> AMD FCH (fusion controller hub) as found on APU2.
> 
> Index: sys/dev/pci/piixpm.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/piixpm.c,v
> retrieving revision 1.42
> diff -u -p -r1.42 piixpm.c
> --- sys/dev/pci/piixpm.c      21 Jan 2020 06:37:24 -0000      1.42
> +++ sys/dev/pci/piixpm.c      8 Feb 2020 04:44:42 -0000
> @@ -54,8 +54,10 @@ struct piixpm_softc {
>       struct device           sc_dev;
>  
>       bus_space_tag_t         sc_iot;
> +     bus_space_tag_t         sc_memt;
>       bus_space_handle_t      sc_ioh;
>       bus_space_handle_t      sc_sb800_ioh;
> +     bus_space_handle_t      sc_wdt_mh;
>       void *                  sc_ih;
>       int                     sc_poll;
>       int                     sc_is_sb800;
> @@ -83,6 +85,8 @@ int piixpm_i2c_exec(void *, i2c_op_t, i2
>  
>  int  piixpm_intr(void *);
>  
> +int  piixpm_wdt_cb(void *arg, int period);
> +
>  struct cfattach piixpm_ca = {
>       sizeof(struct piixpm_softc),
>       piixpm_match,
> @@ -127,7 +131,7 @@ piixpm_attach(struct device *parent, str
>       struct piixpm_softc *sc = (struct piixpm_softc *)self;
>       struct pci_attach_args *pa = aux;
>       bus_space_handle_t ioh;
> -     u_int16_t val, smb0en;
> +     u_int16_t val, smb0en, wdten = 0;
>       bus_addr_t base;
>       pcireg_t conf;
>       pci_intr_handle_t ih;
> @@ -136,6 +140,7 @@ piixpm_attach(struct device *parent, str
>       int numbusses, i;
>  
>       sc->sc_iot = pa->pa_iot;
> +     sc->sc_memt = pa->pa_memt;
>       numbusses = 1;
>  
>       if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
> @@ -160,7 +165,7 @@ piixpm_attach(struct device *parent, str
>  
>               /*
>                * AMD Bolton matches PCI_PRODUCT_AMD_HUDSON2_SMB but
> -              * uses old register layout. Therefor check PCI_REVISION.
> +              * uses old register layout. Therefore check PCI_REVISION.
>                */
>               if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
>                   ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_HUDSON2_SMB &&
> @@ -170,6 +175,7 @@ piixpm_attach(struct device *parent, str
>                           AMDFCH41_PM_DECODE_EN);
>                       val = bus_space_read_1(sc->sc_iot, ioh, 1);
>                       smb0en = val & AMDFCH41_SMBUS_EN;
> +                     wdten = val & AMDFCH41_WDT_EN;
>  
>                       bus_space_write_1(sc->sc_iot, ioh, 0,
>                           AMDFCH41_PM_DECODE_EN + 1);
> @@ -282,7 +288,59 @@ piixpm_attach(struct device *parent, str
>               config_found(self, &iba, iicbus_print);
>       }
>  

Why are you registering the watchdog late and not in the FCH specific
block above? Do other AMD SBx00 or KERNCZ chips support the watchdog in
the same way?

> +     /* Register watchdog */
> +     if (wdten && bus_space_map(sc->sc_memt, AMDFCH41_WDTREG_BASE,
> +         AMDFCH41_WDTREG_SIZE, 0, &sc->sc_wdt_mh) == 0) {
> +             val = bus_space_read_1(sc->sc_memt, sc->sc_wdt_mh,
> +                 AMDFCH41_WDTREG_CTL);
> +             if (val & AMDFCH41_WDTREG_CTL_FIRED) {
> +                     printf("%s watchdog caused previous restart\n",
> +                         sc->sc_dev.dv_xname);
> +                     bus_space_write_1(sc->sc_memt, sc->sc_wdt_mh,
> +                         AMDFCH41_WDTREG_CTL,
> +                         val | AMDFCH41_WDTREG_CTL_FIRED);
> +             }
> +
> +             if (val & AMDFCH41_WDTREG_CTL_DISABLED)
> +                     printf("%s watchdog disabled\n", sc->sc_dev.dv_xname);
> +             else {
> +                     printf("%s watchdog found\n", sc->sc_dev.dv_xname);

The printf used here are non standard. Ideally this printing is folded
into the attach line of piixpm(4), e.g:
piixpm0 at pci0 dev 20 function 0 "AMD Hudson-2 SMBus" rev 0x42: SMI, watchdog
Same for the 'watchdog caused previous restart'. I think the common idiom
is to print ', watchdog' and ', reboot on timeout' for the two cases.

Also move the if (val & AMDFCH41_WDTREG_CTL_FIRED) check after
if (val & AMDFCH41_WDTREG_CTL_DISABLED)

> +
> +                     /* Set 1 second counter period */
> +                     bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 0,
> +                         AMDFCH41_PM_DECODE_EN + 3);
> +                     val = bus_space_read_1(sc->sc_iot, sc->sc_sb800_ioh, 1);
> +                     val = (val & ~AMDFCH41_WDT_MASK) | AMDFCH41_WDT_1S;
> +                     bus_space_write_1(sc->sc_iot, sc->sc_sb800_ioh, 1, val);
> +
> +                     wdog_register(piixpm_wdt_cb, sc);
> +             }
> +     }
> +
>       return;
> +}
> +
> +int
> +piixpm_wdt_cb(void *arg, int period)
> +{
> +     struct piixpm_softc *sc = (struct piixpm_softc *)arg;
> +     u_int16_t val;
> +
> +     val = bus_space_read_1(sc->sc_memt, sc->sc_wdt_mh, AMDFCH41_WDTREG_CTL);
> +
> +     if (period > 0xffff)
> +             period = 0xffff;
> +     if (period > 0) {
> +             bus_space_write_2(sc->sc_memt, sc->sc_wdt_mh,
> +                 AMDFCH41_WDTREG_COUNT, period);
> +             val |= AMDFCH41_WDTREG_CTL_RUN | AMDFCH41_WDTREG_CTL_TRIGGER;
> +     }
> +     else

KNF, move else up

> +             val &= ~AMDFCH41_WDTREG_CTL_RUN;
> +
> +     bus_space_write_1(sc->sc_memt, sc->sc_wdt_mh, AMDFCH41_WDTREG_CTL, val);
> +
> +     return period;
>  }

I think for watchdogs you need at least a DVACT_POWERDOWN activate handler
where wdog_shutdown() is called. Maybe more is needed for DVACT_SUSPEND
and DVACT_RESUME (stop wdog on suspend and restart wdog on resume).

>  int
> Index: sys/dev/pci/piixreg.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/pci/piixreg.h,v
> retrieving revision 1.6
> diff -u -p -r1.6 piixreg.h
> --- sys/dev/pci/piixreg.h     21 Jan 2020 06:37:24 -0000      1.6
> +++ sys/dev/pci/piixreg.h     8 Feb 2020 04:44:42 -0000
> @@ -87,5 +87,19 @@
>  #define AMDFCH41_PM_DECODE_EN        0x00    /* 16-bit register */
>  #define AMDFCH41_PM_PORT_INDEX       0x02
>  #define AMDFCH41_SMBUS_EN    0x10
> +#define AMDFCH41_WDT_EN              0x80
> +#define AMDFCH41_WDT_MASK    0x0f
> +#define AMDFCH41_WDT_32US    0x00
> +#define AMDFCH41_WDT_10MS    0x01
> +#define AMDFCH41_WDT_100MS   0x02
> +#define AMDFCH41_WDT_1S              0x03
> +#define AMDFCH41_WDTREG_BASE 0xfeb00000
> +#define AMDFCH41_WDTREG_SIZE 0x10
> +#define AMDFCH41_WDTREG_CTL  0x00
> +#define AMDFCH41_WDTREG_CTL_RUN              0x01
> +#define AMDFCH41_WDTREG_CTL_FIRED    0x02
> +#define AMDFCH41_WDTREG_CTL_DISABLED 0x08
> +#define AMDFCH41_WDTREG_CTL_TRIGGER  0x80
> +#define AMDFCH41_WDTREG_COUNT        0x04
>  
>  #endif       /* !_DEV_PCI_PIIXREG_H_ */
> 

-- 
:wq Claudio

Reply via email to