1ace1ab86SFrancois Tigeot /*-
2ace1ab86SFrancois Tigeot * Copyright (c) 2004 Texas A&M University
3ace1ab86SFrancois Tigeot * All rights reserved.
4ace1ab86SFrancois Tigeot *
5ace1ab86SFrancois Tigeot * Developer: Wm. Daryl Hawkins
6ace1ab86SFrancois Tigeot *
7ace1ab86SFrancois Tigeot * Redistribution and use in source and binary forms, with or without
8ace1ab86SFrancois Tigeot * modification, are permitted provided that the following conditions
9ace1ab86SFrancois Tigeot * are met:
10ace1ab86SFrancois Tigeot * 1. Redistributions of source code must retain the above copyright
11ace1ab86SFrancois Tigeot * notice, this list of conditions and the following disclaimer.
12ace1ab86SFrancois Tigeot * 2. Redistributions in binary form must reproduce the above copyright
13ace1ab86SFrancois Tigeot * notice, this list of conditions and the following disclaimer in the
14ace1ab86SFrancois Tigeot * documentation and/or other materials provided with the distribution.
15ace1ab86SFrancois Tigeot *
16ace1ab86SFrancois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17ace1ab86SFrancois Tigeot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18ace1ab86SFrancois Tigeot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ace1ab86SFrancois Tigeot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20ace1ab86SFrancois Tigeot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21ace1ab86SFrancois Tigeot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22ace1ab86SFrancois Tigeot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23ace1ab86SFrancois Tigeot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24ace1ab86SFrancois Tigeot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25ace1ab86SFrancois Tigeot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26ace1ab86SFrancois Tigeot * SUCH DAMAGE.
27ace1ab86SFrancois Tigeot */
28ace1ab86SFrancois Tigeot
29ace1ab86SFrancois Tigeot /*
30ace1ab86SFrancois Tigeot * Intel ICH Watchdog Timer (WDT) driver
31ace1ab86SFrancois Tigeot *
32ace1ab86SFrancois Tigeot * Originally developed by Wm. Daryl Hawkins of Texas A&M
33ace1ab86SFrancois Tigeot * Heavily modified by <des@FreeBSD.org>
34ace1ab86SFrancois Tigeot *
35ace1ab86SFrancois Tigeot * This is a tricky one. The ICH WDT can't be treated as a regular PCI
36ace1ab86SFrancois Tigeot * device as it's actually an integrated function of the ICH LPC interface
37ace1ab86SFrancois Tigeot * bridge. Detection is also awkward, because we can only infer the
38ace1ab86SFrancois Tigeot * presence of the watchdog timer from the fact that the machine has an
39ace1ab86SFrancois Tigeot * ICH chipset, or, on ACPI 2.x systems, by the presence of the 'WDDT'
40ace1ab86SFrancois Tigeot * ACPI table (although this driver does not support the ACPI detection
41ace1ab86SFrancois Tigeot * method).
42ace1ab86SFrancois Tigeot *
43ace1ab86SFrancois Tigeot * There is one slight problem on non-ACPI or ACPI 1.x systems: we have no
44ace1ab86SFrancois Tigeot * way of knowing if the WDT is permanently disabled (either by the BIOS
45ace1ab86SFrancois Tigeot * or in hardware).
46ace1ab86SFrancois Tigeot *
47ace1ab86SFrancois Tigeot * The WDT is programmed through I/O registers in the ACPI I/O space.
48ace1ab86SFrancois Tigeot * Intel swears it's always at offset 0x60, so we use that.
49ace1ab86SFrancois Tigeot *
50ace1ab86SFrancois Tigeot * For details about the ICH WDT, see Intel Application Note AP-725
51ace1ab86SFrancois Tigeot * (document no. 292273-001). The WDT is also described in the individual
52ace1ab86SFrancois Tigeot * chipset datasheets, e.g. Intel82801EB ICH5 / 82801ER ICH5R Datasheet
53ace1ab86SFrancois Tigeot * (document no. 252516-001) sections 9.10 and 9.11.
54ace1ab86SFrancois Tigeot *
55ace1ab86SFrancois Tigeot * ICH6/7/8 support by Takeharu KATO <takeharu1219@ybb.ne.jp>
56ace1ab86SFrancois Tigeot *
57ace1ab86SFrancois Tigeot * $FreeBSD: src/sys/dev/ichwd/ichwd.c,v 1.34 2012/01/05 16:27:32 jhb Exp $
58ace1ab86SFrancois Tigeot */
59ace1ab86SFrancois Tigeot
60ace1ab86SFrancois Tigeot #include <sys/param.h>
61ace1ab86SFrancois Tigeot #include <sys/kernel.h>
62ace1ab86SFrancois Tigeot #include <sys/module.h>
63ace1ab86SFrancois Tigeot #include <sys/systm.h>
64ace1ab86SFrancois Tigeot #include <sys/bus.h>
65ace1ab86SFrancois Tigeot #include <sys/rman.h>
66ace1ab86SFrancois Tigeot #include <sys/resource.h>
67ace1ab86SFrancois Tigeot #include <sys/wdog.h>
68ace1ab86SFrancois Tigeot
69ace1ab86SFrancois Tigeot #include <bus/isa/isavar.h>
70ace1ab86SFrancois Tigeot #include <bus/pci/pcivar.h>
71ace1ab86SFrancois Tigeot
72ace1ab86SFrancois Tigeot #include "ichwd.h"
73ace1ab86SFrancois Tigeot
74ace1ab86SFrancois Tigeot static struct ichwd_device ichwd_devices[] = {
75ace1ab86SFrancois Tigeot { DEVICEID_82801AA, "Intel 82801AA watchdog timer", 1 },
76ace1ab86SFrancois Tigeot { DEVICEID_82801AB, "Intel 82801AB watchdog timer", 1 },
77ace1ab86SFrancois Tigeot { DEVICEID_82801BA, "Intel 82801BA watchdog timer", 2 },
78ace1ab86SFrancois Tigeot { DEVICEID_82801BAM, "Intel 82801BAM watchdog timer", 2 },
79ace1ab86SFrancois Tigeot { DEVICEID_82801CA, "Intel 82801CA watchdog timer", 3 },
80ace1ab86SFrancois Tigeot { DEVICEID_82801CAM, "Intel 82801CAM watchdog timer", 3 },
81ace1ab86SFrancois Tigeot { DEVICEID_82801DB, "Intel 82801DB watchdog timer", 4 },
82ace1ab86SFrancois Tigeot { DEVICEID_82801DBM, "Intel 82801DBM watchdog timer", 4 },
83ace1ab86SFrancois Tigeot { DEVICEID_82801E, "Intel 82801E watchdog timer", 5 },
84ace1ab86SFrancois Tigeot { DEVICEID_82801EB, "Intel 82801EB watchdog timer", 5 },
85ace1ab86SFrancois Tigeot { DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer", 5 },
86ace1ab86SFrancois Tigeot { DEVICEID_6300ESB, "Intel 6300ESB watchdog timer", 5 },
87ace1ab86SFrancois Tigeot { DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer", 6 },
88ace1ab86SFrancois Tigeot { DEVICEID_ICH6M, "Intel ICH6M watchdog timer", 6 },
89ace1ab86SFrancois Tigeot { DEVICEID_ICH6W, "Intel ICH6W watchdog timer", 6 },
90ace1ab86SFrancois Tigeot { DEVICEID_ICH7, "Intel ICH7 watchdog timer", 7 },
91ace1ab86SFrancois Tigeot { DEVICEID_ICH7DH, "Intel ICH7DH watchdog timer", 7 },
92ace1ab86SFrancois Tigeot { DEVICEID_ICH7M, "Intel ICH7M watchdog timer", 7 },
93ace1ab86SFrancois Tigeot { DEVICEID_ICH7MDH, "Intel ICH7MDH watchdog timer", 7 },
94ace1ab86SFrancois Tigeot { DEVICEID_NM10, "Intel NM10 watchdog timer", 7 },
95ace1ab86SFrancois Tigeot { DEVICEID_ICH8, "Intel ICH8 watchdog timer", 8 },
96ace1ab86SFrancois Tigeot { DEVICEID_ICH8DH, "Intel ICH8DH watchdog timer", 8 },
97ace1ab86SFrancois Tigeot { DEVICEID_ICH8DO, "Intel ICH8DO watchdog timer", 8 },
98ace1ab86SFrancois Tigeot { DEVICEID_ICH8M, "Intel ICH8M watchdog timer", 8 },
99ace1ab86SFrancois Tigeot { DEVICEID_ICH8ME, "Intel ICH8M-E watchdog timer", 8 },
100ace1ab86SFrancois Tigeot { DEVICEID_63XXESB, "Intel 63XXESB watchdog timer", 8 },
101ace1ab86SFrancois Tigeot { DEVICEID_ICH9, "Intel ICH9 watchdog timer", 9 },
102ace1ab86SFrancois Tigeot { DEVICEID_ICH9DH, "Intel ICH9DH watchdog timer", 9 },
103ace1ab86SFrancois Tigeot { DEVICEID_ICH9DO, "Intel ICH9DO watchdog timer", 9 },
104ace1ab86SFrancois Tigeot { DEVICEID_ICH9M, "Intel ICH9M watchdog timer", 9 },
105ace1ab86SFrancois Tigeot { DEVICEID_ICH9ME, "Intel ICH9M-E watchdog timer", 9 },
106ace1ab86SFrancois Tigeot { DEVICEID_ICH9R, "Intel ICH9R watchdog timer", 9 },
107ace1ab86SFrancois Tigeot { DEVICEID_ICH10, "Intel ICH10 watchdog timer", 10 },
108ace1ab86SFrancois Tigeot { DEVICEID_ICH10D, "Intel ICH10D watchdog timer", 10 },
109ace1ab86SFrancois Tigeot { DEVICEID_ICH10DO, "Intel ICH10DO watchdog timer", 10 },
110ace1ab86SFrancois Tigeot { DEVICEID_ICH10R, "Intel ICH10R watchdog timer", 10 },
111ace1ab86SFrancois Tigeot { DEVICEID_PCH, "Intel PCH watchdog timer", 10 },
112ace1ab86SFrancois Tigeot { DEVICEID_PCHM, "Intel PCH watchdog timer", 10 },
113ace1ab86SFrancois Tigeot { DEVICEID_P55, "Intel P55 watchdog timer", 10 },
114ace1ab86SFrancois Tigeot { DEVICEID_PM55, "Intel PM55 watchdog timer", 10 },
115ace1ab86SFrancois Tigeot { DEVICEID_H55, "Intel H55 watchdog timer", 10 },
116ace1ab86SFrancois Tigeot { DEVICEID_QM57, "Intel QM57 watchdog timer", 10 },
117ace1ab86SFrancois Tigeot { DEVICEID_H57, "Intel H57 watchdog timer", 10 },
118ace1ab86SFrancois Tigeot { DEVICEID_HM55, "Intel HM55 watchdog timer", 10 },
119ace1ab86SFrancois Tigeot { DEVICEID_Q57, "Intel Q57 watchdog timer", 10 },
120ace1ab86SFrancois Tigeot { DEVICEID_HM57, "Intel HM57 watchdog timer", 10 },
121ace1ab86SFrancois Tigeot { DEVICEID_PCHMSFF, "Intel PCHMSFF watchdog timer", 10 },
122ace1ab86SFrancois Tigeot { DEVICEID_QS57, "Intel QS57 watchdog timer", 10 },
123ace1ab86SFrancois Tigeot { DEVICEID_3400, "Intel 3400 watchdog timer", 10 },
124ace1ab86SFrancois Tigeot { DEVICEID_3420, "Intel 3420 watchdog timer", 10 },
125ace1ab86SFrancois Tigeot { DEVICEID_3450, "Intel 3450 watchdog timer", 10 },
126ace1ab86SFrancois Tigeot { DEVICEID_CPT0, "Intel Cougar Point watchdog timer", 10 },
127ace1ab86SFrancois Tigeot { DEVICEID_CPT1, "Intel Cougar Point watchdog timer", 10 },
128ace1ab86SFrancois Tigeot { DEVICEID_CPT2, "Intel Cougar Point watchdog timer", 10 },
129ace1ab86SFrancois Tigeot { DEVICEID_CPT3, "Intel Cougar Point watchdog timer", 10 },
130ace1ab86SFrancois Tigeot { DEVICEID_CPT4, "Intel Cougar Point watchdog timer", 10 },
131ace1ab86SFrancois Tigeot { DEVICEID_CPT5, "Intel Cougar Point watchdog timer", 10 },
132ace1ab86SFrancois Tigeot { DEVICEID_CPT6, "Intel Cougar Point watchdog timer", 10 },
133ace1ab86SFrancois Tigeot { DEVICEID_CPT7, "Intel Cougar Point watchdog timer", 10 },
134ace1ab86SFrancois Tigeot { DEVICEID_CPT8, "Intel Cougar Point watchdog timer", 10 },
135ace1ab86SFrancois Tigeot { DEVICEID_CPT9, "Intel Cougar Point watchdog timer", 10 },
136ace1ab86SFrancois Tigeot { DEVICEID_CPT10, "Intel Cougar Point watchdog timer", 10 },
137ace1ab86SFrancois Tigeot { DEVICEID_CPT11, "Intel Cougar Point watchdog timer", 10 },
138ace1ab86SFrancois Tigeot { DEVICEID_CPT12, "Intel Cougar Point watchdog timer", 10 },
139ace1ab86SFrancois Tigeot { DEVICEID_CPT13, "Intel Cougar Point watchdog timer", 10 },
140ace1ab86SFrancois Tigeot { DEVICEID_CPT14, "Intel Cougar Point watchdog timer", 10 },
141ace1ab86SFrancois Tigeot { DEVICEID_CPT15, "Intel Cougar Point watchdog timer", 10 },
142ace1ab86SFrancois Tigeot { DEVICEID_CPT16, "Intel Cougar Point watchdog timer", 10 },
143ace1ab86SFrancois Tigeot { DEVICEID_CPT17, "Intel Cougar Point watchdog timer", 10 },
144ace1ab86SFrancois Tigeot { DEVICEID_CPT18, "Intel Cougar Point watchdog timer", 10 },
145ace1ab86SFrancois Tigeot { DEVICEID_CPT19, "Intel Cougar Point watchdog timer", 10 },
146ace1ab86SFrancois Tigeot { DEVICEID_CPT20, "Intel Cougar Point watchdog timer", 10 },
147ace1ab86SFrancois Tigeot { DEVICEID_CPT21, "Intel Cougar Point watchdog timer", 10 },
148ace1ab86SFrancois Tigeot { DEVICEID_CPT22, "Intel Cougar Point watchdog timer", 10 },
149ace1ab86SFrancois Tigeot { DEVICEID_CPT23, "Intel Cougar Point watchdog timer", 10 },
150ace1ab86SFrancois Tigeot { DEVICEID_CPT23, "Intel Cougar Point watchdog timer", 10 },
151ace1ab86SFrancois Tigeot { DEVICEID_CPT25, "Intel Cougar Point watchdog timer", 10 },
152ace1ab86SFrancois Tigeot { DEVICEID_CPT26, "Intel Cougar Point watchdog timer", 10 },
153ace1ab86SFrancois Tigeot { DEVICEID_CPT27, "Intel Cougar Point watchdog timer", 10 },
154ace1ab86SFrancois Tigeot { DEVICEID_CPT28, "Intel Cougar Point watchdog timer", 10 },
155ace1ab86SFrancois Tigeot { DEVICEID_CPT29, "Intel Cougar Point watchdog timer", 10 },
156ace1ab86SFrancois Tigeot { DEVICEID_CPT30, "Intel Cougar Point watchdog timer", 10 },
157ace1ab86SFrancois Tigeot { DEVICEID_CPT31, "Intel Cougar Point watchdog timer", 10 },
158ace1ab86SFrancois Tigeot { DEVICEID_PATSBURG_LPC1, "Intel Patsburg watchdog timer", 10 },
159ace1ab86SFrancois Tigeot { DEVICEID_PATSBURG_LPC2, "Intel Patsburg watchdog timer", 10 },
160ace1ab86SFrancois Tigeot { DEVICEID_PPT0, "Intel Panther Point watchdog timer", 10 },
161ace1ab86SFrancois Tigeot { DEVICEID_PPT1, "Intel Panther Point watchdog timer", 10 },
162ace1ab86SFrancois Tigeot { DEVICEID_PPT2, "Intel Panther Point watchdog timer", 10 },
163ace1ab86SFrancois Tigeot { DEVICEID_PPT3, "Intel Panther Point watchdog timer", 10 },
164ace1ab86SFrancois Tigeot { DEVICEID_PPT4, "Intel Panther Point watchdog timer", 10 },
165ace1ab86SFrancois Tigeot { DEVICEID_PPT5, "Intel Panther Point watchdog timer", 10 },
166ace1ab86SFrancois Tigeot { DEVICEID_PPT6, "Intel Panther Point watchdog timer", 10 },
167ace1ab86SFrancois Tigeot { DEVICEID_PPT7, "Intel Panther Point watchdog timer", 10 },
168ace1ab86SFrancois Tigeot { DEVICEID_PPT8, "Intel Panther Point watchdog timer", 10 },
169ace1ab86SFrancois Tigeot { DEVICEID_PPT9, "Intel Panther Point watchdog timer", 10 },
170ace1ab86SFrancois Tigeot { DEVICEID_PPT10, "Intel Panther Point watchdog timer", 10 },
171ace1ab86SFrancois Tigeot { DEVICEID_PPT11, "Intel Panther Point watchdog timer", 10 },
172ace1ab86SFrancois Tigeot { DEVICEID_PPT12, "Intel Panther Point watchdog timer", 10 },
173ace1ab86SFrancois Tigeot { DEVICEID_PPT13, "Intel Panther Point watchdog timer", 10 },
174ace1ab86SFrancois Tigeot { DEVICEID_PPT14, "Intel Panther Point watchdog timer", 10 },
175ace1ab86SFrancois Tigeot { DEVICEID_PPT15, "Intel Panther Point watchdog timer", 10 },
176ace1ab86SFrancois Tigeot { DEVICEID_PPT16, "Intel Panther Point watchdog timer", 10 },
177ace1ab86SFrancois Tigeot { DEVICEID_PPT17, "Intel Panther Point watchdog timer", 10 },
178ace1ab86SFrancois Tigeot { DEVICEID_PPT18, "Intel Panther Point watchdog timer", 10 },
179ace1ab86SFrancois Tigeot { DEVICEID_PPT19, "Intel Panther Point watchdog timer", 10 },
180ace1ab86SFrancois Tigeot { DEVICEID_PPT20, "Intel Panther Point watchdog timer", 10 },
181ace1ab86SFrancois Tigeot { DEVICEID_PPT21, "Intel Panther Point watchdog timer", 10 },
182ace1ab86SFrancois Tigeot { DEVICEID_PPT22, "Intel Panther Point watchdog timer", 10 },
183ace1ab86SFrancois Tigeot { DEVICEID_PPT23, "Intel Panther Point watchdog timer", 10 },
184ace1ab86SFrancois Tigeot { DEVICEID_PPT24, "Intel Panther Point watchdog timer", 10 },
185ace1ab86SFrancois Tigeot { DEVICEID_PPT25, "Intel Panther Point watchdog timer", 10 },
186ace1ab86SFrancois Tigeot { DEVICEID_PPT26, "Intel Panther Point watchdog timer", 10 },
187ace1ab86SFrancois Tigeot { DEVICEID_PPT27, "Intel Panther Point watchdog timer", 10 },
188ace1ab86SFrancois Tigeot { DEVICEID_PPT28, "Intel Panther Point watchdog timer", 10 },
189ace1ab86SFrancois Tigeot { DEVICEID_PPT29, "Intel Panther Point watchdog timer", 10 },
190ace1ab86SFrancois Tigeot { DEVICEID_PPT30, "Intel Panther Point watchdog timer", 10 },
191ace1ab86SFrancois Tigeot { DEVICEID_PPT31, "Intel Panther Point watchdog timer", 10 },
192*35d6cbceSFrançois Tigeot { DEVICEID_LPT0, "Intel Lynx Point watchdog timer", 10 },
193*35d6cbceSFrançois Tigeot { DEVICEID_LPT1, "Intel Lynx Point watchdog timer", 10 },
194*35d6cbceSFrançois Tigeot { DEVICEID_LPT2, "Intel Lynx Point watchdog timer", 10 },
195*35d6cbceSFrançois Tigeot { DEVICEID_LPT3, "Intel Lynx Point watchdog timer", 10 },
196*35d6cbceSFrançois Tigeot { DEVICEID_LPT4, "Intel Lynx Point watchdog timer", 10 },
197*35d6cbceSFrançois Tigeot { DEVICEID_LPT5, "Intel Lynx Point watchdog timer", 10 },
198*35d6cbceSFrançois Tigeot { DEVICEID_LPT6, "Intel Lynx Point watchdog timer", 10 },
199*35d6cbceSFrançois Tigeot { DEVICEID_LPT7, "Intel Lynx Point watchdog timer", 10 },
200*35d6cbceSFrançois Tigeot { DEVICEID_LPT8, "Intel Lynx Point watchdog timer", 10 },
201*35d6cbceSFrançois Tigeot { DEVICEID_LPT9, "Intel Lynx Point watchdog timer", 10 },
202*35d6cbceSFrançois Tigeot { DEVICEID_LPT10, "Intel Lynx Point watchdog timer", 10 },
203*35d6cbceSFrançois Tigeot { DEVICEID_LPT11, "Intel Lynx Point watchdog timer", 10 },
204*35d6cbceSFrançois Tigeot { DEVICEID_LPT12, "Intel Lynx Point watchdog timer", 10 },
205*35d6cbceSFrançois Tigeot { DEVICEID_LPT13, "Intel Lynx Point watchdog timer", 10 },
206*35d6cbceSFrançois Tigeot { DEVICEID_LPT14, "Intel Lynx Point watchdog timer", 10 },
207*35d6cbceSFrançois Tigeot { DEVICEID_LPT15, "Intel Lynx Point watchdog timer", 10 },
208*35d6cbceSFrançois Tigeot { DEVICEID_LPT16, "Intel Lynx Point watchdog timer", 10 },
209*35d6cbceSFrançois Tigeot { DEVICEID_LPT17, "Intel Lynx Point watchdog timer", 10 },
210*35d6cbceSFrançois Tigeot { DEVICEID_LPT18, "Intel Lynx Point watchdog timer", 10 },
211*35d6cbceSFrançois Tigeot { DEVICEID_LPT19, "Intel Lynx Point watchdog timer", 10 },
212*35d6cbceSFrançois Tigeot { DEVICEID_LPT20, "Intel Lynx Point watchdog timer", 10 },
213*35d6cbceSFrançois Tigeot { DEVICEID_LPT21, "Intel Lynx Point watchdog timer", 10 },
214*35d6cbceSFrançois Tigeot { DEVICEID_LPT22, "Intel Lynx Point watchdog timer", 10 },
215*35d6cbceSFrançois Tigeot { DEVICEID_LPT23, "Intel Lynx Point watchdog timer", 10 },
216*35d6cbceSFrançois Tigeot { DEVICEID_LPT24, "Intel Lynx Point watchdog timer", 10 },
217*35d6cbceSFrançois Tigeot { DEVICEID_LPT25, "Intel Lynx Point watchdog timer", 10 },
218*35d6cbceSFrançois Tigeot { DEVICEID_LPT26, "Intel Lynx Point watchdog timer", 10 },
219*35d6cbceSFrançois Tigeot { DEVICEID_LPT27, "Intel Lynx Point watchdog timer", 10 },
220*35d6cbceSFrançois Tigeot { DEVICEID_LPT28, "Intel Lynx Point watchdog timer", 10 },
221*35d6cbceSFrançois Tigeot { DEVICEID_LPT29, "Intel Lynx Point watchdog timer", 10 },
222*35d6cbceSFrançois Tigeot { DEVICEID_LPT30, "Intel Lynx Point watchdog timer", 10 },
223*35d6cbceSFrançois Tigeot { DEVICEID_LPT31, "Intel Lynx Point watchdog timer", 10 },
224*35d6cbceSFrançois Tigeot { DEVICEID_WCPT2, "Intel Wildcat Point watchdog timer", 10 },
225*35d6cbceSFrançois Tigeot { DEVICEID_WCPT4, "Intel Wildcat Point watchdog timer", 10 },
226*35d6cbceSFrançois Tigeot { DEVICEID_WCPT6, "Intel Wildcat Point watchdog timer", 10 },
227ace1ab86SFrancois Tigeot { DEVICEID_DH89XXCC_LPC, "Intel DH89xxCC watchdog timer", 10 },
228*35d6cbceSFrançois Tigeot { DEVICEID_COLETOCRK_LPC, "Intel Coleto Creek watchdog timer", 10 },
229ace1ab86SFrancois Tigeot { 0, NULL, 0 },
230ace1ab86SFrancois Tigeot };
231ace1ab86SFrancois Tigeot
232ace1ab86SFrancois Tigeot static devclass_t ichwd_devclass;
233ace1ab86SFrancois Tigeot
234ace1ab86SFrancois Tigeot static struct ichwd_softc ichwd_sc;
235ace1ab86SFrancois Tigeot
236ace1ab86SFrancois Tigeot #define ichwd_read_tco_1(sc, off) \
237ace1ab86SFrancois Tigeot bus_read_1((sc)->tco_res, (off))
238ace1ab86SFrancois Tigeot #define ichwd_read_tco_2(sc, off) \
239ace1ab86SFrancois Tigeot bus_read_2((sc)->tco_res, (off))
240ace1ab86SFrancois Tigeot #define ichwd_read_tco_4(sc, off) \
241ace1ab86SFrancois Tigeot bus_read_4((sc)->tco_res, (off))
242ace1ab86SFrancois Tigeot #define ichwd_read_smi_4(sc, off) \
243ace1ab86SFrancois Tigeot bus_read_4((sc)->smi_res, (off))
244ace1ab86SFrancois Tigeot #define ichwd_read_gcs_4(sc, off) \
245ace1ab86SFrancois Tigeot bus_read_4((sc)->gcs_res, (off))
246ace1ab86SFrancois Tigeot
247ace1ab86SFrancois Tigeot #define ichwd_write_tco_1(sc, off, val) \
248ace1ab86SFrancois Tigeot bus_write_1((sc)->tco_res, (off), (val))
249ace1ab86SFrancois Tigeot #define ichwd_write_tco_2(sc, off, val) \
250ace1ab86SFrancois Tigeot bus_write_2((sc)->tco_res, (off), (val))
251ace1ab86SFrancois Tigeot #define ichwd_write_tco_4(sc, off, val) \
252ace1ab86SFrancois Tigeot bus_write_4((sc)->tco_res, (off), (val))
253ace1ab86SFrancois Tigeot #define ichwd_write_smi_4(sc, off, val) \
254ace1ab86SFrancois Tigeot bus_write_4((sc)->smi_res, (off), (val))
255ace1ab86SFrancois Tigeot #define ichwd_write_gcs_4(sc, off, val) \
256ace1ab86SFrancois Tigeot bus_write_4((sc)->gcs_res, (off), (val))
257ace1ab86SFrancois Tigeot
258ace1ab86SFrancois Tigeot #define ichwd_verbose_printf(dev, ...) \
259ace1ab86SFrancois Tigeot do { \
260ace1ab86SFrancois Tigeot if (bootverbose) \
261ace1ab86SFrancois Tigeot device_printf(dev, __VA_ARGS__);\
262ace1ab86SFrancois Tigeot } while (0)
263ace1ab86SFrancois Tigeot
264ace1ab86SFrancois Tigeot /*
265ace1ab86SFrancois Tigeot * Disable the watchdog timeout SMI handler.
266ace1ab86SFrancois Tigeot *
267ace1ab86SFrancois Tigeot * Apparently, some BIOSes install handlers that reset or disable the
268ace1ab86SFrancois Tigeot * watchdog timer instead of resetting the system, so we disable the SMI
269ace1ab86SFrancois Tigeot * (by clearing the SMI_TCO_EN bit of the SMI_EN register) to prevent this
270ace1ab86SFrancois Tigeot * from happening.
271ace1ab86SFrancois Tigeot */
272ace1ab86SFrancois Tigeot static __inline void
ichwd_smi_disable(struct ichwd_softc * sc)273ace1ab86SFrancois Tigeot ichwd_smi_disable(struct ichwd_softc *sc)
274ace1ab86SFrancois Tigeot {
275ace1ab86SFrancois Tigeot ichwd_write_smi_4(sc, SMI_EN, ichwd_read_smi_4(sc, SMI_EN) & ~SMI_TCO_EN);
276ace1ab86SFrancois Tigeot }
277ace1ab86SFrancois Tigeot
278ace1ab86SFrancois Tigeot /*
279ace1ab86SFrancois Tigeot * Enable the watchdog timeout SMI handler. See above for details.
280ace1ab86SFrancois Tigeot */
281ace1ab86SFrancois Tigeot static __inline void
ichwd_smi_enable(struct ichwd_softc * sc)282ace1ab86SFrancois Tigeot ichwd_smi_enable(struct ichwd_softc *sc)
283ace1ab86SFrancois Tigeot {
284ace1ab86SFrancois Tigeot ichwd_write_smi_4(sc, SMI_EN, ichwd_read_smi_4(sc, SMI_EN) | SMI_TCO_EN);
285ace1ab86SFrancois Tigeot }
286ace1ab86SFrancois Tigeot
287ace1ab86SFrancois Tigeot /*
288ace1ab86SFrancois Tigeot * Check if the watchdog SMI triggering is enabled.
289ace1ab86SFrancois Tigeot */
290ace1ab86SFrancois Tigeot static __inline int
ichwd_smi_is_enabled(struct ichwd_softc * sc)291ace1ab86SFrancois Tigeot ichwd_smi_is_enabled(struct ichwd_softc *sc)
292ace1ab86SFrancois Tigeot {
293ace1ab86SFrancois Tigeot return ((ichwd_read_smi_4(sc, SMI_EN) & SMI_TCO_EN) != 0);
294ace1ab86SFrancois Tigeot }
295ace1ab86SFrancois Tigeot
296ace1ab86SFrancois Tigeot /*
297ace1ab86SFrancois Tigeot * Reset the watchdog status bits.
298ace1ab86SFrancois Tigeot */
299ace1ab86SFrancois Tigeot static __inline void
ichwd_sts_reset(struct ichwd_softc * sc)300ace1ab86SFrancois Tigeot ichwd_sts_reset(struct ichwd_softc *sc)
301ace1ab86SFrancois Tigeot {
302ace1ab86SFrancois Tigeot /*
303ace1ab86SFrancois Tigeot * The watchdog status bits are set to 1 by the hardware to
304ace1ab86SFrancois Tigeot * indicate various conditions. They can be cleared by software
305ace1ab86SFrancois Tigeot * by writing a 1, not a 0.
306ace1ab86SFrancois Tigeot */
307ace1ab86SFrancois Tigeot ichwd_write_tco_2(sc, TCO1_STS, TCO_TIMEOUT);
308ace1ab86SFrancois Tigeot /*
309ace1ab86SFrancois Tigeot * According to Intel's docs, clearing SECOND_TO_STS and BOOT_STS must
310ace1ab86SFrancois Tigeot * be done in two separate operations.
311ace1ab86SFrancois Tigeot */
312ace1ab86SFrancois Tigeot ichwd_write_tco_2(sc, TCO2_STS, TCO_SECOND_TO_STS);
313ace1ab86SFrancois Tigeot ichwd_write_tco_2(sc, TCO2_STS, TCO_BOOT_STS);
314ace1ab86SFrancois Tigeot }
315ace1ab86SFrancois Tigeot
316ace1ab86SFrancois Tigeot /*
317ace1ab86SFrancois Tigeot * Enable the watchdog timer by clearing the TCO_TMR_HALT bit in the
318ace1ab86SFrancois Tigeot * TCO1_CNT register. This is complicated by the need to preserve bit 9
319ace1ab86SFrancois Tigeot * of that same register, and the requirement that all other bits must be
320ace1ab86SFrancois Tigeot * written back as zero.
321ace1ab86SFrancois Tigeot */
322ace1ab86SFrancois Tigeot static __inline void
ichwd_tmr_enable(struct ichwd_softc * sc)323ace1ab86SFrancois Tigeot ichwd_tmr_enable(struct ichwd_softc *sc)
324ace1ab86SFrancois Tigeot {
325ace1ab86SFrancois Tigeot uint16_t cnt;
326ace1ab86SFrancois Tigeot
327ace1ab86SFrancois Tigeot cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE;
328ace1ab86SFrancois Tigeot ichwd_write_tco_2(sc, TCO1_CNT, cnt & ~TCO_TMR_HALT);
329ace1ab86SFrancois Tigeot sc->active = 1;
330ace1ab86SFrancois Tigeot ichwd_verbose_printf(sc->device, "timer enabled\n");
331ace1ab86SFrancois Tigeot }
332ace1ab86SFrancois Tigeot
333ace1ab86SFrancois Tigeot /*
334ace1ab86SFrancois Tigeot * Disable the watchdog timer. See above for details.
335ace1ab86SFrancois Tigeot */
336ace1ab86SFrancois Tigeot static __inline void
ichwd_tmr_disable(struct ichwd_softc * sc)337ace1ab86SFrancois Tigeot ichwd_tmr_disable(struct ichwd_softc *sc)
338ace1ab86SFrancois Tigeot {
339ace1ab86SFrancois Tigeot uint16_t cnt;
340ace1ab86SFrancois Tigeot
341ace1ab86SFrancois Tigeot cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE;
342ace1ab86SFrancois Tigeot ichwd_write_tco_2(sc, TCO1_CNT, cnt | TCO_TMR_HALT);
343ace1ab86SFrancois Tigeot sc->active = 0;
344ace1ab86SFrancois Tigeot ichwd_verbose_printf(sc->device, "timer disabled\n");
345ace1ab86SFrancois Tigeot }
346ace1ab86SFrancois Tigeot
347ace1ab86SFrancois Tigeot /*
348ace1ab86SFrancois Tigeot * Reload the watchdog timer: writing anything to any of the lower five
349ace1ab86SFrancois Tigeot * bits of the TCO_RLD register reloads the timer from the last value
350ace1ab86SFrancois Tigeot * written to TCO_TMR.
351ace1ab86SFrancois Tigeot */
352ace1ab86SFrancois Tigeot static __inline void
ichwd_tmr_reload(struct ichwd_softc * sc)353ace1ab86SFrancois Tigeot ichwd_tmr_reload(struct ichwd_softc *sc)
354ace1ab86SFrancois Tigeot {
355ace1ab86SFrancois Tigeot if (sc->ich_version <= 5)
356ace1ab86SFrancois Tigeot ichwd_write_tco_1(sc, TCO_RLD, 1);
357ace1ab86SFrancois Tigeot else
358ace1ab86SFrancois Tigeot ichwd_write_tco_2(sc, TCO_RLD, 1);
359ace1ab86SFrancois Tigeot }
360ace1ab86SFrancois Tigeot
361ace1ab86SFrancois Tigeot /*
362ace1ab86SFrancois Tigeot * Set the initial timeout value. Note that this must always be followed
363ace1ab86SFrancois Tigeot * by a reload.
364ace1ab86SFrancois Tigeot */
365ace1ab86SFrancois Tigeot static __inline void
ichwd_tmr_set(struct ichwd_softc * sc,unsigned int timeout)366ace1ab86SFrancois Tigeot ichwd_tmr_set(struct ichwd_softc *sc, unsigned int timeout)
367ace1ab86SFrancois Tigeot {
368ace1ab86SFrancois Tigeot
369ace1ab86SFrancois Tigeot if (timeout < TCO_RLD_TMR_MIN)
370ace1ab86SFrancois Tigeot timeout = TCO_RLD_TMR_MIN;
371ace1ab86SFrancois Tigeot
372ace1ab86SFrancois Tigeot if (sc->ich_version <= 5) {
373ace1ab86SFrancois Tigeot uint8_t tmr_val8 = ichwd_read_tco_1(sc, TCO_TMR1);
374ace1ab86SFrancois Tigeot
375ace1ab86SFrancois Tigeot tmr_val8 &= (~TCO_RLD1_TMR_MAX & 0xff);
376ace1ab86SFrancois Tigeot if (timeout > TCO_RLD1_TMR_MAX)
377ace1ab86SFrancois Tigeot timeout = TCO_RLD1_TMR_MAX;
378ace1ab86SFrancois Tigeot tmr_val8 |= timeout;
379ace1ab86SFrancois Tigeot ichwd_write_tco_1(sc, TCO_TMR1, tmr_val8);
380ace1ab86SFrancois Tigeot } else {
381ace1ab86SFrancois Tigeot uint16_t tmr_val16 = ichwd_read_tco_2(sc, TCO_TMR2);
382ace1ab86SFrancois Tigeot
383ace1ab86SFrancois Tigeot tmr_val16 &= (~TCO_RLD2_TMR_MAX & 0xffff);
384ace1ab86SFrancois Tigeot if (timeout > TCO_RLD2_TMR_MAX)
385ace1ab86SFrancois Tigeot timeout = TCO_RLD2_TMR_MAX;
386ace1ab86SFrancois Tigeot tmr_val16 |= timeout;
387ace1ab86SFrancois Tigeot ichwd_write_tco_2(sc, TCO_TMR2, tmr_val16);
388ace1ab86SFrancois Tigeot }
389ace1ab86SFrancois Tigeot
390ace1ab86SFrancois Tigeot sc->timeout = timeout;
391ace1ab86SFrancois Tigeot
392ace1ab86SFrancois Tigeot ichwd_verbose_printf(sc->device, "timeout set to %u ticks\n", timeout);
393ace1ab86SFrancois Tigeot }
394ace1ab86SFrancois Tigeot
395ace1ab86SFrancois Tigeot static __inline int
ichwd_clear_noreboot(struct ichwd_softc * sc)396ace1ab86SFrancois Tigeot ichwd_clear_noreboot(struct ichwd_softc *sc)
397ace1ab86SFrancois Tigeot {
398ace1ab86SFrancois Tigeot uint32_t status;
399ace1ab86SFrancois Tigeot int rc = 0;
400ace1ab86SFrancois Tigeot
401ace1ab86SFrancois Tigeot /* try to clear the NO_REBOOT bit */
402ace1ab86SFrancois Tigeot if (sc->ich_version <= 5) {
403ace1ab86SFrancois Tigeot status = pci_read_config(sc->ich, ICH_GEN_STA, 1);
404ace1ab86SFrancois Tigeot status &= ~ICH_GEN_STA_NO_REBOOT;
405ace1ab86SFrancois Tigeot pci_write_config(sc->ich, ICH_GEN_STA, status, 1);
406ace1ab86SFrancois Tigeot status = pci_read_config(sc->ich, ICH_GEN_STA, 1);
407ace1ab86SFrancois Tigeot if (status & ICH_GEN_STA_NO_REBOOT)
408ace1ab86SFrancois Tigeot rc = EIO;
409ace1ab86SFrancois Tigeot } else {
410ace1ab86SFrancois Tigeot status = ichwd_read_gcs_4(sc, 0);
411ace1ab86SFrancois Tigeot status &= ~ICH_GCS_NO_REBOOT;
412ace1ab86SFrancois Tigeot ichwd_write_gcs_4(sc, 0, status);
413ace1ab86SFrancois Tigeot status = ichwd_read_gcs_4(sc, 0);
414ace1ab86SFrancois Tigeot if (status & ICH_GCS_NO_REBOOT)
415ace1ab86SFrancois Tigeot rc = EIO;
416ace1ab86SFrancois Tigeot }
417ace1ab86SFrancois Tigeot
418ace1ab86SFrancois Tigeot if (rc)
419ace1ab86SFrancois Tigeot device_printf(sc->device,
420ace1ab86SFrancois Tigeot "ICH WDT present but disabled in BIOS or hardware\n");
421ace1ab86SFrancois Tigeot
422ace1ab86SFrancois Tigeot return (rc);
423ace1ab86SFrancois Tigeot }
424ace1ab86SFrancois Tigeot
425ace1ab86SFrancois Tigeot static device_t
ichwd_find_ich_lpc_bridge(struct ichwd_device ** id_p)426ace1ab86SFrancois Tigeot ichwd_find_ich_lpc_bridge(struct ichwd_device **id_p)
427ace1ab86SFrancois Tigeot {
428ace1ab86SFrancois Tigeot struct ichwd_device *id;
429ace1ab86SFrancois Tigeot device_t ich = NULL;
430ace1ab86SFrancois Tigeot
431ace1ab86SFrancois Tigeot /* look for an ICH LPC interface bridge */
432ace1ab86SFrancois Tigeot for (id = ichwd_devices; id->desc != NULL; ++id)
433ace1ab86SFrancois Tigeot if ((ich = pci_find_device(VENDORID_INTEL, id->device)) != NULL)
434ace1ab86SFrancois Tigeot break;
435ace1ab86SFrancois Tigeot
436ace1ab86SFrancois Tigeot if (ich == NULL)
437ace1ab86SFrancois Tigeot return (NULL);
438ace1ab86SFrancois Tigeot
439ace1ab86SFrancois Tigeot ichwd_verbose_printf(ich, "found ICH%d or equivalent chipset: %s\n",
440ace1ab86SFrancois Tigeot id->version, id->desc);
441ace1ab86SFrancois Tigeot
442ace1ab86SFrancois Tigeot if (id_p)
443ace1ab86SFrancois Tigeot *id_p = id;
444ace1ab86SFrancois Tigeot
445ace1ab86SFrancois Tigeot return (ich);
446ace1ab86SFrancois Tigeot }
447ace1ab86SFrancois Tigeot
448ace1ab86SFrancois Tigeot /*
449ace1ab86SFrancois Tigeot * Look for an ICH LPC interface bridge. If one is found, register an
450ace1ab86SFrancois Tigeot * ichwd device. There can be only one.
451ace1ab86SFrancois Tigeot */
452ace1ab86SFrancois Tigeot static void
ichwd_identify(driver_t * driver,device_t parent)453ace1ab86SFrancois Tigeot ichwd_identify(driver_t *driver, device_t parent)
454ace1ab86SFrancois Tigeot {
455ace1ab86SFrancois Tigeot struct ichwd_device *id_p;
456ace1ab86SFrancois Tigeot device_t ich = NULL;
457ace1ab86SFrancois Tigeot device_t dev;
458ace1ab86SFrancois Tigeot uint32_t rcba;
459ace1ab86SFrancois Tigeot int rc;
460ace1ab86SFrancois Tigeot
461ace1ab86SFrancois Tigeot ich = ichwd_find_ich_lpc_bridge(&id_p);
462ace1ab86SFrancois Tigeot if (ich == NULL)
463ace1ab86SFrancois Tigeot return;
464ace1ab86SFrancois Tigeot
465ace1ab86SFrancois Tigeot /* good, add child to bus */
466ace1ab86SFrancois Tigeot if ((dev = device_find_child(parent, driver->name, 0)) == NULL)
467ace1ab86SFrancois Tigeot dev = BUS_ADD_CHILD(parent, parent, 0, driver->name, 0);
468ace1ab86SFrancois Tigeot
469ace1ab86SFrancois Tigeot if (dev == NULL)
470ace1ab86SFrancois Tigeot return;
471ace1ab86SFrancois Tigeot
472ace1ab86SFrancois Tigeot device_set_desc_copy(dev, id_p->desc);
473ace1ab86SFrancois Tigeot
474ace1ab86SFrancois Tigeot if (id_p->version >= 6) {
475ace1ab86SFrancois Tigeot /* get RCBA (root complex base address) */
476ace1ab86SFrancois Tigeot rcba = pci_read_config(ich, ICH_RCBA, 4);
477ace1ab86SFrancois Tigeot rc = bus_set_resource(ich, SYS_RES_MEMORY, 0,
478ace1ab86SFrancois Tigeot (rcba & 0xffffc000) + ICH_GCS_OFFSET, ICH_GCS_SIZE, -1);
479ace1ab86SFrancois Tigeot if (rc)
480ace1ab86SFrancois Tigeot ichwd_verbose_printf(dev,
481ace1ab86SFrancois Tigeot "Can not set memory resource for RCBA\n");
482ace1ab86SFrancois Tigeot }
483ace1ab86SFrancois Tigeot }
484ace1ab86SFrancois Tigeot
485ace1ab86SFrancois Tigeot static int
ich_watchdog(void * unused,int period)486ace1ab86SFrancois Tigeot ich_watchdog(void *unused, int period)
487ace1ab86SFrancois Tigeot {
488ace1ab86SFrancois Tigeot unsigned int timeout;
489ace1ab86SFrancois Tigeot
490ace1ab86SFrancois Tigeot /* convert from seconds to WDT ticks */
491ace1ab86SFrancois Tigeot timeout = (period * 1000) / ICHWD_TICK;
492ace1ab86SFrancois Tigeot
493ace1ab86SFrancois Tigeot ichwd_tmr_set(&ichwd_sc, timeout);
494ace1ab86SFrancois Tigeot ichwd_tmr_reload(&ichwd_sc);
495ace1ab86SFrancois Tigeot
496ace1ab86SFrancois Tigeot return period;
497ace1ab86SFrancois Tigeot }
498ace1ab86SFrancois Tigeot
499ace1ab86SFrancois Tigeot static struct watchdog ich_wdog = {
500ace1ab86SFrancois Tigeot .name = "Intel ICH",
501ace1ab86SFrancois Tigeot .wdog_fn = ich_watchdog,
502ace1ab86SFrancois Tigeot .arg = NULL,
503ace1ab86SFrancois Tigeot .period_max = (TCO_RLD1_TMR_MAX * ICHWD_TICK) / 1000,
504ace1ab86SFrancois Tigeot };
505ace1ab86SFrancois Tigeot
506ace1ab86SFrancois Tigeot static int
ichwd_probe(device_t dev)507ace1ab86SFrancois Tigeot ichwd_probe(device_t dev)
508ace1ab86SFrancois Tigeot {
509ace1ab86SFrancois Tigeot
510ace1ab86SFrancois Tigeot /* Do not claim some ISA PnP device by accident. */
511ace1ab86SFrancois Tigeot if (isa_get_logicalid(dev) != 0)
512ace1ab86SFrancois Tigeot return (ENXIO);
513ace1ab86SFrancois Tigeot return (0);
514ace1ab86SFrancois Tigeot }
515ace1ab86SFrancois Tigeot
516ace1ab86SFrancois Tigeot static int
ichwd_attach(device_t dev)517ace1ab86SFrancois Tigeot ichwd_attach(device_t dev)
518ace1ab86SFrancois Tigeot {
519ace1ab86SFrancois Tigeot struct ichwd_softc *sc;
520ace1ab86SFrancois Tigeot struct ichwd_device *id_p;
521ace1ab86SFrancois Tigeot device_t ich;
522ace1ab86SFrancois Tigeot unsigned int pmbase = 0;
523ace1ab86SFrancois Tigeot
524ace1ab86SFrancois Tigeot sc = &ichwd_sc;
525ace1ab86SFrancois Tigeot sc->device = dev;
526ace1ab86SFrancois Tigeot
527ace1ab86SFrancois Tigeot ich = ichwd_find_ich_lpc_bridge(&id_p);
528ace1ab86SFrancois Tigeot if (ich == NULL) {
529ace1ab86SFrancois Tigeot device_printf(sc->device, "Can not find ICH device.\n");
530ace1ab86SFrancois Tigeot goto fail;
531ace1ab86SFrancois Tigeot }
532ace1ab86SFrancois Tigeot sc->ich = ich;
533ace1ab86SFrancois Tigeot sc->ich_version = id_p->version;
534ace1ab86SFrancois Tigeot
535ace1ab86SFrancois Tigeot /* get ACPI base address */
536ace1ab86SFrancois Tigeot pmbase = pci_read_config(ich, ICH_PMBASE, 2) & ICH_PMBASE_MASK;
537ace1ab86SFrancois Tigeot if (pmbase == 0) {
538ace1ab86SFrancois Tigeot device_printf(dev, "ICH PMBASE register is empty\n");
539ace1ab86SFrancois Tigeot goto fail;
540ace1ab86SFrancois Tigeot }
541ace1ab86SFrancois Tigeot
542ace1ab86SFrancois Tigeot /* allocate I/O register space */
543ace1ab86SFrancois Tigeot sc->smi_rid = 0;
544ace1ab86SFrancois Tigeot sc->smi_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->smi_rid,
545ace1ab86SFrancois Tigeot pmbase + SMI_BASE, pmbase + SMI_BASE + SMI_LEN - 1, SMI_LEN,
546ace1ab86SFrancois Tigeot RF_ACTIVE | RF_SHAREABLE);
547ace1ab86SFrancois Tigeot if (sc->smi_res == NULL) {
548ace1ab86SFrancois Tigeot device_printf(dev, "unable to reserve SMI registers\n");
549ace1ab86SFrancois Tigeot goto fail;
550ace1ab86SFrancois Tigeot }
551ace1ab86SFrancois Tigeot
552ace1ab86SFrancois Tigeot sc->tco_rid = 1;
553ace1ab86SFrancois Tigeot sc->tco_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->tco_rid,
554ace1ab86SFrancois Tigeot pmbase + TCO_BASE, pmbase + TCO_BASE + TCO_LEN - 1, TCO_LEN,
555ace1ab86SFrancois Tigeot RF_ACTIVE | RF_SHAREABLE);
556ace1ab86SFrancois Tigeot if (sc->tco_res == NULL) {
557ace1ab86SFrancois Tigeot device_printf(dev, "unable to reserve TCO registers\n");
558ace1ab86SFrancois Tigeot goto fail;
559ace1ab86SFrancois Tigeot }
560ace1ab86SFrancois Tigeot
561ace1ab86SFrancois Tigeot sc->gcs_rid = 0;
562ace1ab86SFrancois Tigeot if (sc->ich_version >= 6) {
563ace1ab86SFrancois Tigeot sc->gcs_res = bus_alloc_resource_any(ich, SYS_RES_MEMORY,
564ace1ab86SFrancois Tigeot &sc->gcs_rid, RF_ACTIVE|RF_SHAREABLE);
565ace1ab86SFrancois Tigeot if (sc->gcs_res == NULL) {
566ace1ab86SFrancois Tigeot device_printf(dev, "unable to reserve GCS registers\n");
567ace1ab86SFrancois Tigeot goto fail;
568ace1ab86SFrancois Tigeot }
569ace1ab86SFrancois Tigeot }
570ace1ab86SFrancois Tigeot
571ace1ab86SFrancois Tigeot if (ichwd_clear_noreboot(sc) != 0)
572ace1ab86SFrancois Tigeot goto fail;
573ace1ab86SFrancois Tigeot
574ace1ab86SFrancois Tigeot ichwd_verbose_printf(dev, "%s (ICH%d or equivalent)\n",
575ace1ab86SFrancois Tigeot device_get_desc(dev), sc->ich_version);
576ace1ab86SFrancois Tigeot
577ace1ab86SFrancois Tigeot /*
578ace1ab86SFrancois Tigeot * Determine if we are coming up after a watchdog-induced reset. Some
579ace1ab86SFrancois Tigeot * BIOSes may clear this bit at bootup, preventing us from reporting
580ace1ab86SFrancois Tigeot * this case on such systems. We clear this bit in ichwd_sts_reset().
581ace1ab86SFrancois Tigeot */
582ace1ab86SFrancois Tigeot if ((ichwd_read_tco_2(sc, TCO2_STS) & TCO_SECOND_TO_STS) != 0)
583ace1ab86SFrancois Tigeot device_printf(dev,
584ace1ab86SFrancois Tigeot "resuming after hardware watchdog timeout\n");
585ace1ab86SFrancois Tigeot
586ace1ab86SFrancois Tigeot /* reset the watchdog status registers */
587ace1ab86SFrancois Tigeot ichwd_sts_reset(sc);
588ace1ab86SFrancois Tigeot
589ace1ab86SFrancois Tigeot /* make sure the WDT starts out inactive */
590ace1ab86SFrancois Tigeot ichwd_tmr_disable(sc);
591ace1ab86SFrancois Tigeot
592ace1ab86SFrancois Tigeot /* register the watchdog event handler */
593ace1ab86SFrancois Tigeot wdog_register(&ich_wdog);
594ace1ab86SFrancois Tigeot
595ace1ab86SFrancois Tigeot /* disable the SMI handler */
596ace1ab86SFrancois Tigeot sc->smi_enabled = ichwd_smi_is_enabled(sc);
597ace1ab86SFrancois Tigeot ichwd_smi_disable(sc);
598ace1ab86SFrancois Tigeot
599ace1ab86SFrancois Tigeot /* and enable the watchdog */
600ace1ab86SFrancois Tigeot ichwd_tmr_enable(sc);
601ace1ab86SFrancois Tigeot
602ace1ab86SFrancois Tigeot return (0);
603ace1ab86SFrancois Tigeot fail:
604ace1ab86SFrancois Tigeot sc = device_get_softc(dev);
605ace1ab86SFrancois Tigeot if (sc->tco_res != NULL)
606ace1ab86SFrancois Tigeot bus_release_resource(dev, SYS_RES_IOPORT,
607ace1ab86SFrancois Tigeot sc->tco_rid, sc->tco_res);
608ace1ab86SFrancois Tigeot if (sc->smi_res != NULL)
609ace1ab86SFrancois Tigeot bus_release_resource(dev, SYS_RES_IOPORT,
610ace1ab86SFrancois Tigeot sc->smi_rid, sc->smi_res);
611ace1ab86SFrancois Tigeot if (sc->gcs_res != NULL)
612ace1ab86SFrancois Tigeot bus_release_resource(ich, SYS_RES_MEMORY,
613ace1ab86SFrancois Tigeot sc->gcs_rid, sc->gcs_res);
614ace1ab86SFrancois Tigeot
615ace1ab86SFrancois Tigeot return (ENXIO);
616ace1ab86SFrancois Tigeot }
617ace1ab86SFrancois Tigeot
618ace1ab86SFrancois Tigeot static int
ichwd_detach(device_t dev)619ace1ab86SFrancois Tigeot ichwd_detach(device_t dev)
620ace1ab86SFrancois Tigeot {
621ace1ab86SFrancois Tigeot struct ichwd_softc *sc;
622ace1ab86SFrancois Tigeot device_t ich = NULL;
623ace1ab86SFrancois Tigeot
624ace1ab86SFrancois Tigeot sc = &ichwd_sc;
625ace1ab86SFrancois Tigeot
626ace1ab86SFrancois Tigeot /* halt the watchdog timer */
627ace1ab86SFrancois Tigeot if (sc->active)
628ace1ab86SFrancois Tigeot ichwd_tmr_disable(sc);
629ace1ab86SFrancois Tigeot
630ace1ab86SFrancois Tigeot /* enable the SMI handler */
631ace1ab86SFrancois Tigeot if (sc->smi_enabled != 0)
632ace1ab86SFrancois Tigeot ichwd_smi_enable(sc);
633ace1ab86SFrancois Tigeot
634ace1ab86SFrancois Tigeot /* deregister event handler */
635ace1ab86SFrancois Tigeot wdog_unregister(&ich_wdog);
636ace1ab86SFrancois Tigeot
637ace1ab86SFrancois Tigeot /* reset the watchdog status registers */
638ace1ab86SFrancois Tigeot ichwd_sts_reset(sc);
639ace1ab86SFrancois Tigeot
640ace1ab86SFrancois Tigeot /* deallocate I/O register space */
641ace1ab86SFrancois Tigeot bus_release_resource(dev, SYS_RES_IOPORT, sc->tco_rid, sc->tco_res);
642ace1ab86SFrancois Tigeot bus_release_resource(dev, SYS_RES_IOPORT, sc->smi_rid, sc->smi_res);
643ace1ab86SFrancois Tigeot
644ace1ab86SFrancois Tigeot /* deallocate memory resource */
645ace1ab86SFrancois Tigeot ich = ichwd_find_ich_lpc_bridge(NULL);
646ace1ab86SFrancois Tigeot if (sc->gcs_res && ich)
647ace1ab86SFrancois Tigeot bus_release_resource(ich, SYS_RES_MEMORY, sc->gcs_rid, sc->gcs_res);
648ace1ab86SFrancois Tigeot
649ace1ab86SFrancois Tigeot return (0);
650ace1ab86SFrancois Tigeot }
651ace1ab86SFrancois Tigeot
652ace1ab86SFrancois Tigeot static device_method_t ichwd_methods[] = {
653ace1ab86SFrancois Tigeot DEVMETHOD(device_identify, ichwd_identify),
654ace1ab86SFrancois Tigeot DEVMETHOD(device_probe, ichwd_probe),
655ace1ab86SFrancois Tigeot DEVMETHOD(device_attach, ichwd_attach),
656ace1ab86SFrancois Tigeot DEVMETHOD(device_detach, ichwd_detach),
657ace1ab86SFrancois Tigeot DEVMETHOD(device_shutdown, ichwd_detach),
658d3c9c58eSSascha Wildner DEVMETHOD_END
659ace1ab86SFrancois Tigeot };
660ace1ab86SFrancois Tigeot
661ace1ab86SFrancois Tigeot static driver_t ichwd_driver = {
662ace1ab86SFrancois Tigeot "ichwd",
663ace1ab86SFrancois Tigeot ichwd_methods,
664ace1ab86SFrancois Tigeot 0
665ace1ab86SFrancois Tigeot };
666ace1ab86SFrancois Tigeot
667ace1ab86SFrancois Tigeot DRIVER_MODULE(ichwd, isa, ichwd_driver, ichwd_devclass, NULL, NULL);
668ace1ab86SFrancois Tigeot MODULE_VERSION(ichwd, 1);
669