| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $$NetBSD: pwdog.c,v 1.3 2011/08/26 10:30:47 mbalmer Exp $ */ | | 1 | /* $$NetBSD: pwdog.c,v 1.4 2011/08/26 13:29:56 mbalmer Exp $ */ |
2 | /* $OpenBSD: pwdog.c,v 1.7 2010/04/08 00:23:53 tedu Exp $ */ | | 2 | /* $OpenBSD: pwdog.c,v 1.7 2010/04/08 00:23:53 tedu Exp $ */ |
3 | | | 3 | |
4 | /* | | 4 | /* |
5 | * Copyright (c) 2006, 2011 Marc Balmer <mbalmer@NetBSD.org> | | 5 | * Copyright (c) 2006, 2011 Marc Balmer <mbalmer@NetBSD.org> |
6 | * | | 6 | * |
7 | * Permission to use, copy, modify, and distribute this software for any | | 7 | * Permission to use, copy, modify, and distribute this software for any |
8 | * purpose with or without fee is hereby granted, provided that the above | | 8 | * purpose with or without fee is hereby granted, provided that the above |
9 | * copyright notice and this permission notice appear in all copies. | | 9 | * copyright notice and this permission notice appear in all copies. |
10 | * | | 10 | * |
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | | 11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | | 12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | | 13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | | 14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| @@ -44,26 +44,27 @@ struct pwdog_softc { | | | @@ -44,26 +44,27 @@ struct pwdog_softc { |
44 | }; | | 44 | }; |
45 | | | 45 | |
46 | /* registers */ | | 46 | /* registers */ |
47 | #define PWDOG_ACTIVATE 0 | | 47 | #define PWDOG_ACTIVATE 0 |
48 | #define PWDOG_DISABLE 1 | | 48 | #define PWDOG_DISABLE 1 |
49 | | | 49 | |
50 | /* maximum timeout period in seconds */ | | 50 | /* maximum timeout period in seconds */ |
51 | #define PWDOG_MAX_PERIOD (12*60) /* 12 minutes */ | | 51 | #define PWDOG_MAX_PERIOD (12*60) /* 12 minutes */ |
52 | | | 52 | |
53 | static int pwdog_match(device_t, cfdata_t, void *); | | 53 | static int pwdog_match(device_t, cfdata_t, void *); |
54 | static void pwdog_attach(device_t, device_t, void *); | | 54 | static void pwdog_attach(device_t, device_t, void *); |
55 | static int pwdog_detach(device_t, int); | | 55 | static int pwdog_detach(device_t, int); |
56 | static bool pwdog_suspend(device_t, const pmf_qual_t *); | | 56 | static bool pwdog_suspend(device_t, const pmf_qual_t *); |
| | | 57 | static bool pwdog_resume(device_t, const pmf_qual_t *); |
57 | static int pwdog_setmode(struct sysmon_wdog *); | | 58 | static int pwdog_setmode(struct sysmon_wdog *); |
58 | static int pwdog_tickle(struct sysmon_wdog *); | | 59 | static int pwdog_tickle(struct sysmon_wdog *); |
59 | | | 60 | |
60 | CFATTACH_DECL_NEW( | | 61 | CFATTACH_DECL_NEW( |
61 | pwdog, | | 62 | pwdog, |
62 | sizeof(struct pwdog_softc), | | 63 | sizeof(struct pwdog_softc), |
63 | pwdog_match, | | 64 | pwdog_match, |
64 | pwdog_attach, | | 65 | pwdog_attach, |
65 | pwdog_detach, | | 66 | pwdog_detach, |
66 | NULL | | 67 | NULL |
67 | ); | | 68 | ); |
68 | | | 69 | |
69 | static int | | 70 | static int |
| @@ -86,63 +87,81 @@ pwdog_attach(device_t parent, device_t s | | | @@ -86,63 +87,81 @@ pwdog_attach(device_t parent, device_t s |
86 | | | 87 | |
87 | memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START); | | 88 | memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START); |
88 | if (pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, &sc->sc_iot, | | 89 | if (pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0, &sc->sc_iot, |
89 | &sc->sc_ioh, NULL, &sc->sc_iosize)) { | | 90 | &sc->sc_ioh, NULL, &sc->sc_iosize)) { |
90 | aprint_error("\n"); | | 91 | aprint_error("\n"); |
91 | aprint_error_dev(self, "PCI %s region not found\n", | | 92 | aprint_error_dev(self, "PCI %s region not found\n", |
92 | memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory"); | | 93 | memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory"); |
93 | return; | | 94 | return; |
94 | } | | 95 | } |
95 | printf("\n"); | | 96 | printf("\n"); |
96 | | | 97 | |
97 | sc->sc_dev = self; | | 98 | sc->sc_dev = self; |
98 | | | 99 | |
99 | pmf_device_register(self, pwdog_suspend, NULL); | | 100 | pmf_device_register(self, pwdog_suspend, pwdog_resume); |
100 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, PWDOG_DISABLE, 0); | | 101 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, PWDOG_DISABLE, 0); |
101 | | | 102 | |
102 | sc->sc_smw.smw_name = device_xname(self); | | 103 | sc->sc_smw.smw_name = device_xname(self); |
103 | sc->sc_smw.smw_cookie = sc; | | 104 | sc->sc_smw.smw_cookie = sc; |
104 | sc->sc_smw.smw_setmode = pwdog_setmode; | | 105 | sc->sc_smw.smw_setmode = pwdog_setmode; |
105 | sc->sc_smw.smw_tickle = pwdog_tickle; | | 106 | sc->sc_smw.smw_tickle = pwdog_tickle; |
106 | sc->sc_smw.smw_period = PWDOG_MAX_PERIOD; | | 107 | sc->sc_smw.smw_period = PWDOG_MAX_PERIOD; |
107 | | | 108 | |
108 | if (sysmon_wdog_register(&sc->sc_smw)) | | 109 | if (sysmon_wdog_register(&sc->sc_smw)) |
109 | aprint_error_dev(self, "couldn't register with sysmon\n"); | | 110 | aprint_error_dev(self, "couldn't register with sysmon\n"); |
110 | else | | 111 | else |
111 | sc->sc_smw_valid = true; | | 112 | sc->sc_smw_valid = true; |
112 | } | | 113 | } |
113 | | | 114 | |
114 | static int | | 115 | static int |
115 | pwdog_detach(device_t self, int flags) | | 116 | pwdog_detach(device_t self, int flags) |
116 | { | | 117 | { |
117 | struct pwdog_softc *sc = device_private(self); | | 118 | struct pwdog_softc *sc = device_private(self); |
118 | | | 119 | |
| | | 120 | /* XXX check flags & DETACH_FORCE (or DETACH_SHUTDOWN)? */ |
119 | if (sc->sc_smw_valid) { | | 121 | if (sc->sc_smw_valid) { |
120 | if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) | | 122 | if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) |
121 | != WDOG_MODE_DISARMED) | | 123 | != WDOG_MODE_DISARMED) |
122 | return EBUSY; | | 124 | return EBUSY; |
123 | | | 125 | |
124 | sysmon_wdog_unregister(&sc->sc_smw); | | 126 | sysmon_wdog_unregister(&sc->sc_smw); |
125 | sc->sc_smw_valid = false; | | 127 | sc->sc_smw_valid = false; |
126 | } | | 128 | } |
127 | | | 129 | |
128 | pmf_device_deregister(self); | | 130 | pmf_device_deregister(self); |
129 | | | 131 | |
130 | if (sc->sc_iosize) | | 132 | if (sc->sc_iosize) |
131 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); | | 133 | bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); |
132 | return 0; | | 134 | return 0; |
133 | } | | 135 | } |
134 | | | 136 | |
135 | static bool | | 137 | static bool |
| | | 138 | pwdog_resume(device_t self, const pmf_qual_t *qual) |
| | | 139 | { |
| | | 140 | struct pwdog_softc *sc = device_private(self); |
| | | 141 | |
| | | 142 | if (sc->sc_smw_valid == false) |
| | | 143 | return true; |
| | | 144 | |
| | | 145 | /* |
| | | 146 | * suspend is inhibited when the watchdog timer was armed, |
| | | 147 | * so when we end up here, the watchdog is disabled; program the |
| | | 148 | * hardware accordingly. |
| | | 149 | */ |
| | | 150 | bus_space_write_1(sc->sc_iot, sc->sc_ioh, PWDOG_DISABLE, 0); |
| | | 151 | return true; |
| | | 152 | } |
| | | 153 | |
| | | 154 | static bool |
136 | pwdog_suspend(device_t self, const pmf_qual_t *qual) | | 155 | pwdog_suspend(device_t self, const pmf_qual_t *qual) |
137 | { | | 156 | { |
138 | struct pwdog_softc *sc = device_private(self); | | 157 | struct pwdog_softc *sc = device_private(self); |
139 | | | 158 | |
140 | if (sc->sc_smw_valid == false) | | 159 | if (sc->sc_smw_valid == false) |
141 | return true; | | 160 | return true; |
142 | | | 161 | |
143 | if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) != WDOG_MODE_DISARMED) | | 162 | if ((sc->sc_smw.smw_mode & WDOG_MODE_MASK) != WDOG_MODE_DISARMED) |
144 | return false; | | 163 | return false; |
145 | | | 164 | |
146 | return true; | | 165 | return true; |
147 | } | | 166 | } |
148 | | | 167 | |