tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: power management and pseudo-devices



(Resent, this time with attachment!)

On Sun, 18 Jul 2010, Quentin Garnier wrote:

On Sun, Jul 18, 2010 at 07:14:57AM -0700, Paul Goyette wrote:
Currently, pseudo-devices are silently attached to the device tree
without giving the driver any access to the associated device_t
structure.  As a result, the pseudo-device driver is unable to
access much of the pmf framework.  In particular, the pseudo-device
cannot register a suspend/resume/shutdown handler, nor can it
register to receive pmf event notifications.

It seems to me that it would be reasonably useful for pseudo-devices
to be capabile of participating in pmf.  One particular example I've
run into recently is the swwdog pseudo-device.  Other watchdog
drivers can prevent a suspend if their timer is armed, but since
swwdog is only a pseudo-device it cannot register a pmf handler.

Convert it to a defpseudodev then.

I've done this, and it works! Diffs attached. Any objections to committing them?


-------------------------------------------------------------------------
| Paul Goyette     | PGP Key fingerprint:     | E-mail addresses:       |
| Customer Service | FA29 0E3B 35AF E8AE 6651 | paul at whooppee.com    |
| Network Engineer | 0786 F758 55DE 53BA 7731 | pgoyette at juniper.net |
| Kernel Developer |                          | pgoyette at netbsd.org  |
-------------------------------------------------------------------------
Index: files.sysmon
===================================================================
RCS file: /cvsroot/src/sys/dev/sysmon/files.sysmon,v
retrieving revision 1.11
diff -u -p -r1.11 files.sysmon
--- files.sysmon        30 Jan 2010 21:55:28 -0000      1.11
+++ files.sysmon        18 Jul 2010 19:30:23 -0000
@@ -18,5 +18,5 @@ file  dev/sysmon/sysmon_wdog.c        sysmon_wdo
 file   dev/sysmon/sysmon.c             sysmon_envsys | sysmon_wdog |
                                        sysmon_power
 
-defpseudo swwdog: sysmon_wdog
+defpseudodev swwdog: sysmon_wdog
 file    dev/sysmon/swwdog.c            swwdog
Index: swwdog.c
===================================================================
RCS file: /cvsroot/src/sys/dev/sysmon/swwdog.c,v
retrieving revision 1.9
diff -u -p -r1.9 swwdog.c
--- swwdog.c    31 Jan 2010 02:54:56 -0000      1.9
+++ swwdog.c    18 Jul 2010 19:30:23 -0000
@@ -44,20 +44,28 @@ __KERNEL_RCSID(0, "$NetBSD: swwdog.c,v 1
 #include <sys/callout.h>
 #include <sys/device.h>
 #include <sys/kernel.h>
+#include <sys/kmem.h>
 #include <sys/reboot.h>
 #include <sys/systm.h>
 #include <sys/wdog.h>
 #include <dev/sysmon/sysmonvar.h>
 
-#define NSWWDOG 1
 struct swwdog_softc {
+       device_t sc_dev;
        struct sysmon_wdog sc_smw;
        struct callout sc_c;
-       char sc_name[20];
        int sc_wdog_armed;
-} sc_wdog[NSWWDOG];
+};
 
-void   swwdogattach(int);
+struct swwdog_softc *sc_swwdog = NULL;
+
+extern struct cfdriver swwdog_cd;
+
+void           swwdogattach(int);
+
+static int     swwdog_match(device_t, cfdata_t, void *);
+static void    swwdog_attach(device_t, device_t, void *);
+static int     swwdog_detach(device_t, int);
 
 static int swwdog_setmode(struct sysmon_wdog *);
 static int swwdog_tickle(struct sysmon_wdog *);
@@ -71,17 +79,63 @@ int swwdog_reboot = 0;              /* set for panic
 
 #define        SWDOG_DEFAULT   60              /* 60-second default period */
 
+CFATTACH_DECL_NEW(swwdog, sizeof(struct swwdog_softc),
+       swwdog_match, swwdog_attach, swwdog_detach, NULL);
+
 void
-swwdogattach(int count __unused)
+swwdogattach(int n)
 {
-       int i;
+       int err;
+       cfdata_t cf;
+
+       if (n > 1)
+               aprint_verbose("%s: ignoring count of %d\n",
+                   swwdog_cd.cd_name, n);
+
+       err = config_cfattach_attach(swwdog_cd.cd_name, &swwdog_ca);
+       if (err) {
+               aprint_error("%s: couldn't register cfattach: %d\n",
+                   swwdog_cd.cd_name, err);
+               config_cfdriver_detach(&swwdog_cd);
+               return;
+       }
+
+       cf = kmem_alloc(sizeof(struct cfdata), KM_NOSLEEP);
+       if (cf == NULL)
+               aprint_error("%s: couldn't allocate cfdata\n",
+                   swwdog_cd.cd_name);
+       else {
+               cf->cf_name = swwdog_cd.cd_name;
+               cf->cf_atname = swwdog_cd.cd_name;
+               cf->cf_unit = 0;
+               cf->cf_fstate = FSTATE_STAR;
 
-       for (i = 0; i < NSWWDOG; i++) {
-               struct swwdog_softc *sc = &sc_wdog[i];
+               (void)config_attach_pseudo(cf);
+       }
+
+       return;
+}
 
-               snprintf(sc->sc_name, sizeof sc->sc_name, "swwdog%d", i);
-               printf("%s: ", sc->sc_name);
-               sc->sc_smw.smw_name = sc->sc_name;
+static int
+swwdog_match(device_t parent, cfdata_t data, void *aux)
+{
+       /* Match unless we already have a swwdog */
+       if (sc_swwdog == NULL)
+               return 1;
+
+       return 0;
+}
+
+static void
+swwdog_attach(device_t parent, device_t self, void *aux)
+{
+       struct swwdog_softc *sc = device_private(self);
+
+       if (sc_swwdog == NULL) {
+               sc_swwdog = sc;
+
+               sc->sc_dev = self;
+               sc->sc_smw.smw_name = device_xname(self);
                sc->sc_smw.smw_cookie = sc;
                sc->sc_smw.smw_setmode = swwdog_setmode;
                sc->sc_smw.smw_tickle = swwdog_tickle;
@@ -90,14 +144,30 @@ swwdogattach(int count __unused)
                callout_setfunc(&sc->sc_c, swwdog_panic, sc);
 
                if (sysmon_wdog_register(&sc->sc_smw) == 0)
-                       printf("software watchdog initialized\n");
+                       aprint_normal_dev(self,
+                           "software watchdog initialized\n");
                else
-                       printf("unable to register software watchdog "
-                           "with sysmon\n");
+                       aprint_error_dev(self, "unable to register "
+                           "software watchdog with sysmon\n");
+
+               if (!pmf_device_register(self, NULL, NULL))
+                       aprint_error_dev(self, "couldn't establish power "
+                           "handler\n");
        }
 }
 
 static int
+swwdog_detach(device_t self, int flags)
+{
+       struct swwdog_softc *sc = device_private(self);
+
+       swwdog_disarm(sc);
+       callout_destroy(&sc->sc_c);
+
+       return 1;
+}
+
+static int
 swwdog_setmode(struct sysmon_wdog *smw)
 {
        struct swwdog_softc *sc = smw->smw_cookie;
@@ -150,7 +220,7 @@ swwdog_panic(void *vsc)
        swwdog_reboot = 1;
        callout_schedule(&sc->sc_c, 60 * hz);   /* deliberate double-panic */
 
-       printf("%s: %d second timer expired\n", sc->sc_name,
+       printf("%s: %d second timer expired\n", device_xname(sc->sc_dev),
            sc->sc_smw.smw_period);
 
        if (do_panic)


Home | Main Index | Thread Index | Old Index