Merge from vendor branch GROFF:
[dragonfly.git] / sys / dev / powermng / ichsmb / ichsmb.c
1
2 /*
3  * ichsmb.c
4  *
5  * Copyright (c) 2000 Whistle Communications, Inc.
6  * All rights reserved.
7  * 
8  * Subject to the following obligations and disclaimer of warranty, use and
9  * redistribution of this software, in source or object code forms, with or
10  * without modifications are expressly permitted by Whistle Communications;
11  * provided, however, that:
12  * 1. Any and all reproductions of the source or object code must include the
13  *    copyright notice above and the following disclaimer of warranties; and
14  * 2. No rights are granted, in any manner or form, to use Whistle
15  *    Communications, Inc. trademarks, including the mark "WHISTLE
16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
17  *    such appears in the above copyright notice or in the software.
18  * 
19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
35  * OF SUCH DAMAGE.
36  *
37  * Author: Archie Cobbs <archie@freebsd.org>
38  *
39  * $FreeBSD: src/sys/dev/ichsmb/ichsmb.c,v 1.1.2.1 2000/10/09 00:52:43 archie Exp $
40  * $DragonFly: src/sys/dev/powermng/ichsmb/ichsmb.c,v 1.6 2005/06/10 23:29:32 dillon Exp $
41  */
42
43 /*
44  * Support for the SMBus controller logical device which is part of the
45  * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips.
46  */
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/errno.h>
52 #include <sys/syslog.h>
53 #include <sys/bus.h>
54 #include <sys/thread2.h>
55
56 #include <machine/bus.h>
57 #include <sys/rman.h>
58 #include <machine/resource.h>
59
60 #include <bus/smbus/smbconf.h>
61
62 #include "ichsmb_var.h"
63 #include "ichsmb_reg.h"
64
65 /*
66  * Enable debugging by defining ICHSMB_DEBUG to a non-zero value.
67  */
68 #define ICHSMB_DEBUG    0
69 #if ICHSMB_DEBUG != 0 && defined(__GNUC__)
70 #define DBG(fmt, args...)       \
71         do { log(LOG_DEBUG, "%s: " fmt, __func__ , ## args); } while (0)
72 #else
73 #define DBG(fmt, args...)       do { } while (0)
74 #endif
75
76 /*
77  * Our child device driver name
78  */
79 #define DRIVER_SMBUS    "smbus"
80
81 /*
82  * Internal functions
83  */
84 static int ichsmb_wait(sc_p sc);
85
86 /********************************************************************
87                 BUS-INDEPENDENT BUS METHODS
88 ********************************************************************/
89
90 /*
91  * Handle probe-time duties that are independent of the bus
92  * our device lives on.
93  */
94 int
95 ichsmb_probe(device_t dev)
96 {
97         device_t smb;
98
99         /* Add child: an instance of the "smbus" device */
100         if ((smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) {
101                 log(LOG_ERR, "%s: no \"%s\" child found\n",
102                     device_get_nameunit(dev), DRIVER_SMBUS);
103                 return (ENXIO);
104         }
105         return (0);
106 }
107
108 /*
109  * Handle attach-time duties that are independent of the bus
110  * our device lives on.
111  */
112 int
113 ichsmb_attach(device_t dev)
114 {
115         const sc_p sc = device_get_softc(dev);
116         int error;
117
118         /* Clear interrupt conditions */
119         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, 0xff);
120
121         /* Add "smbus" child */
122         if ((error = bus_generic_attach(dev)) != 0) {
123                 log(LOG_ERR, "%s: failed to attach child: %d\n",
124                     device_get_nameunit(dev), error);
125                 error = ENXIO;
126         }
127
128         /* Done */
129         return (error);
130 }
131
132 /********************************************************************
133                         SMBUS METHODS
134 ********************************************************************/
135
136 int 
137 ichsmb_callback(device_t dev, int index, caddr_t data)
138 {
139         int smb_error = 0;
140
141         DBG("index=%d how=%d\n", index, data ? *(int *)data : -1);
142         switch (index) {
143         case SMB_REQUEST_BUS:
144                 break;
145         case SMB_RELEASE_BUS:
146                 break;
147         default:
148                 smb_error = SMB_EABORT; /* XXX */
149                 break;
150         }
151         DBG("smb_error=%d\n", smb_error);
152         return (smb_error);
153 }
154
155 int
156 ichsmb_quick(device_t dev, u_char slave, int how)
157 {
158         const sc_p sc = device_get_softc(dev);
159         int smb_error;
160
161         DBG("slave=0x%02x how=%d\n", slave, how);
162         KASSERT(sc->ich_cmd == -1,
163             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
164         switch (how) {
165         case SMB_QREAD:
166         case SMB_QWRITE:
167                 crit_enter();
168                 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK;
169                 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
170                     (slave << 1) | (how == SMB_QREAD ?
171                         ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE));
172                 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
173                     ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
174                 smb_error = ichsmb_wait(sc);
175                 crit_exit();
176                 break;
177         default:
178                 smb_error = SMB_ENOTSUPP;
179         }
180         DBG("smb_error=%d\n", smb_error);
181         return (smb_error);
182 }
183
184 int
185 ichsmb_sendb(device_t dev, u_char slave, char byte)
186 {
187         const sc_p sc = device_get_softc(dev);
188         int smb_error;
189
190         DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte);
191         KASSERT(sc->ich_cmd == -1,
192             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
193         crit_enter();
194         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
195         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
196             (slave << 1) | ICH_XMIT_SLVA_WRITE);
197         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, byte);
198         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
199             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
200         smb_error = ichsmb_wait(sc);
201         crit_exit();
202         DBG("smb_error=%d\n", smb_error);
203         return (smb_error);
204 }
205
206 int
207 ichsmb_recvb(device_t dev, u_char slave, char *byte)
208 {
209         const sc_p sc = device_get_softc(dev);
210         int smb_error;
211
212         DBG("slave=0x%02x\n", slave);
213         KASSERT(sc->ich_cmd == -1,
214             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
215         crit_enter();
216         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
217         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
218             (slave << 1) | ICH_XMIT_SLVA_READ);
219         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
220             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
221         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
222                 *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0);
223         crit_exit();
224         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
225         return (smb_error);
226 }
227
228 int
229 ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
230 {
231         const sc_p sc = device_get_softc(dev);
232         int smb_error;
233
234         DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n",
235             slave, (u_char)cmd, (u_char)byte);
236         KASSERT(sc->ich_cmd == -1,
237             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
238         crit_enter();
239         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
240         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
241             (slave << 1) | ICH_XMIT_SLVA_WRITE);
242         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
243         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, byte);
244         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
245             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
246         smb_error = ichsmb_wait(sc);
247         crit_exit();
248         DBG("smb_error=%d\n", smb_error);
249         return (smb_error);
250 }
251
252 int
253 ichsmb_writew(device_t dev, u_char slave, char cmd, short word)
254 {
255         const sc_p sc = device_get_softc(dev);
256         int smb_error;
257
258         DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n",
259             slave, (u_char)cmd, (u_int16_t)word);
260         KASSERT(sc->ich_cmd == -1,
261             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
262         crit_enter();
263         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
264         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
265             (slave << 1) | ICH_XMIT_SLVA_WRITE);
266         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
267         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, word & 0xff);
268         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, word >> 8);
269         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
270             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
271         smb_error = ichsmb_wait(sc);
272         crit_exit();
273         DBG("smb_error=%d\n", smb_error);
274         return (smb_error);
275 }
276
277 int
278 ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
279 {
280         const sc_p sc = device_get_softc(dev);
281         int smb_error;
282
283         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
284         KASSERT(sc->ich_cmd == -1,
285             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
286         crit_enter();
287         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
288         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
289             (slave << 1) | ICH_XMIT_SLVA_READ);
290         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
291         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
292             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
293         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
294                 *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0);
295         crit_exit();
296         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
297         return (smb_error);
298 }
299
300 int
301 ichsmb_readw(device_t dev, u_char slave, char cmd, short *word)
302 {
303         const sc_p sc = device_get_softc(dev);
304         int smb_error;
305
306         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
307         KASSERT(sc->ich_cmd == -1,
308             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
309         crit_enter();
310         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
311         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
312             (slave << 1) | ICH_XMIT_SLVA_READ);
313         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
314         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
315             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
316         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
317                 *word = (bus_space_read_1(sc->io_bst,
318                         sc->io_bsh, ICH_D0) & 0xff)
319                   | (bus_space_read_1(sc->io_bst,
320                         sc->io_bsh, ICH_D1) << 8);
321         }
322         crit_exit();
323         DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word);
324         return (smb_error);
325 }
326
327 int
328 ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
329 {
330         const sc_p sc = device_get_softc(dev);
331         int smb_error;
332
333         DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n",
334             slave, (u_char)cmd, (u_int16_t)sdata);
335         KASSERT(sc->ich_cmd == -1,
336             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
337         crit_enter();
338         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL;
339         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
340             (slave << 1) | ICH_XMIT_SLVA_WRITE);
341         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
342         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, sdata & 0xff);
343         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, sdata >> 8);
344         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
345             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
346         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
347                 *rdata = (bus_space_read_1(sc->io_bst,
348                         sc->io_bsh, ICH_D0) & 0xff)
349                   | (bus_space_read_1(sc->io_bst,
350                         sc->io_bsh, ICH_D1) << 8);
351         }
352         crit_exit();
353         DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata);
354         return (smb_error);
355 }
356
357 int
358 ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
359 {
360         const sc_p sc = device_get_softc(dev);
361         int smb_error;
362
363         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
364 #if ICHSMB_DEBUG
365 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
366         {
367             u_char *p;
368
369             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
370                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
371                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
372                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
373                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 
374                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
375             }
376         }
377 #undef DISP
378 #endif
379         KASSERT(sc->ich_cmd == -1,
380             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
381         if (count < 1 || count > 32)
382                 return (EINVAL);
383         bcopy(buf, sc->block_data, count);
384         sc->block_count = count;
385         sc->block_index = 1;
386         sc->block_write = 1;
387
388         crit_enter();
389         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
390         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
391             (slave << 1) | ICH_XMIT_SLVA_WRITE);
392         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
393         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count);
394         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_BLOCK_DB, buf[0]);
395         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
396             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
397         smb_error = ichsmb_wait(sc);
398         crit_exit();
399         DBG("smb_error=%d\n", smb_error);
400         return (smb_error);
401 }
402
403 int
404 ichsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
405 {
406         const sc_p sc = device_get_softc(dev);
407         int smb_error;
408
409         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
410         KASSERT(sc->ich_cmd == -1,
411             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
412         if (count < 1 || count > 32)
413                 return (EINVAL);
414         bzero(sc->block_data, sizeof(sc->block_data));
415         sc->block_count = count;
416         sc->block_index = 0;
417         sc->block_write = 0;
418
419         crit_enter();
420         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
421         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA,
422             (slave << 1) | ICH_XMIT_SLVA_READ);
423         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd);
424         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); /* XXX? */
425         bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT,
426             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
427         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
428                 bcopy(sc->block_data, buf, sc->block_count);
429         crit_exit();
430         DBG("smb_error=%d\n", smb_error);
431 #if ICHSMB_DEBUG
432 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
433         {
434             u_char *p;
435
436             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
437                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
438                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
439                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
440                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 
441                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
442             }
443         }
444 #undef DISP
445 #endif
446         return (smb_error);
447 }
448
449 /********************************************************************
450                         OTHER FUNCTIONS
451 ********************************************************************/
452
453 /*
454  * This table describes what interrupts we should ever expect to
455  * see after each ICH command, not including the SMBALERT interrupt.
456  */
457 static const u_int8_t ichsmb_state_irqs[] = {
458         /* quick */
459         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
460         /* byte */
461         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
462         /* byte data */
463         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
464         /* word data */
465         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
466         /* process call */
467         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
468         /* block */
469         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
470             | ICH_HST_STA_BYTE_DONE_STS),
471         /* i2c read (not used) */
472         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
473             | ICH_HST_STA_BYTE_DONE_STS)
474 };
475
476 /*
477  * Interrupt handler. This handler is bus-independent. Note that our
478  * interrupt may be shared, so we must handle "false" interrupts.
479  */
480 void
481 ichsmb_device_intr(void *cookie)
482 {
483         const sc_p sc = cookie;
484         const device_t dev = sc->dev;
485         const int maxloops = 16;
486         u_int8_t status;
487         u_int8_t ok_bits;
488         int cmd_index;
489         int count;
490
491         crit_enter();
492         for (count = 0; count < maxloops; count++) {
493
494                 /* Get and reset status bits */
495                 status = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA);
496 #if ICHSMB_DEBUG
497                 if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY))
498                     || count > 0) {
499                         DBG("%d stat=0x%02x\n", count, status);
500                 }
501 #endif
502                 status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY);
503                 if (status == 0)
504                         break;
505
506                 /* Check for unexpected interrupt */
507                 ok_bits = ICH_HST_STA_SMBALERT_STS;
508                 cmd_index = sc->ich_cmd >> 2;
509                 if (sc->ich_cmd != -1) {
510                         KASSERT(cmd_index < sizeof(ichsmb_state_irqs),
511                             ("%s: ich_cmd=%d", device_get_nameunit(dev),
512                             sc->ich_cmd));
513                         ok_bits |= ichsmb_state_irqs[cmd_index];
514                 }
515                 if ((status & ~ok_bits) != 0) {
516                         log(LOG_ERR, "%s: irq 0x%02x during %d\n",
517                             device_get_nameunit(dev), status, cmd_index);
518                         bus_space_write_1(sc->io_bst, sc->io_bsh,
519                             ICH_HST_STA, (status & ~ok_bits));
520                         continue;
521                 }
522
523                 /* Handle SMBALERT interrupt */
524                 if (status & ICH_HST_STA_SMBALERT_STS) {
525                         static int smbalert_count = 16;
526                         if (smbalert_count > 0) {
527                                 log(LOG_WARNING, "%s: SMBALERT# rec'd\n",
528                                     device_get_nameunit(dev));
529                                 if (--smbalert_count == 0) {
530                                         log(LOG_WARNING,
531                                             "%s: not logging anymore\n",
532                                             device_get_nameunit(dev));
533                                 }
534                         }
535                 }
536
537                 /* Check for bus error */
538                 if (status & ICH_HST_STA_BUS_ERR) {
539                         sc->smb_error = SMB_ECOLLI;     /* XXX SMB_EBUSERR? */
540                         goto finished;
541                 }
542
543                 /* Check for device error */
544                 if (status & ICH_HST_STA_DEV_ERR) {
545                         sc->smb_error = SMB_ENOACK;     /* or SMB_ETIMEOUT? */
546                         goto finished;
547                 }
548
549                 /* Check for byte completion in block transfer */
550                 if (status & ICH_HST_STA_BYTE_DONE_STS) {
551                         if (sc->block_write) {
552                                 if (sc->block_index < sc->block_count) {
553
554                                         /* Write next byte */
555                                         bus_space_write_1(sc->io_bst,
556                                             sc->io_bsh, ICH_BLOCK_DB,
557                                             sc->block_data[sc->block_index++]);
558                                 }
559                         } else {
560
561                                 /* First interrupt, get the count also */
562                                 if (sc->block_index == 0) {
563                                         sc->block_count = bus_space_read_1(
564                                             sc->io_bst, sc->io_bsh, ICH_D0);
565                                 }
566
567                                 /* Get next byte, if any */
568                                 if (sc->block_index < sc->block_count) {
569
570                                         /* Read next byte */
571                                         sc->block_data[sc->block_index++] =
572                                             bus_space_read_1(sc->io_bst,
573                                               sc->io_bsh, ICH_BLOCK_DB);
574
575                                         /* Set "LAST_BYTE" bit before reading
576                                            the last byte of block data */
577                                         if (sc->block_index
578                                             >= sc->block_count - 1) {
579                                                 bus_space_write_1(sc->io_bst,
580                                                     sc->io_bsh, ICH_HST_CNT,
581                                                     ICH_HST_CNT_LAST_BYTE
582                                                         | ICH_HST_CNT_INTREN
583                                                         | sc->ich_cmd);
584                                         }
585                                 }
586                         }
587                 }
588
589                 /* Check command completion */
590                 if (status & ICH_HST_STA_INTR) {
591                         sc->smb_error = SMB_ENOERR;
592 finished:
593                         sc->ich_cmd = -1;
594                         bus_space_write_1(sc->io_bst, sc->io_bsh,
595                             ICH_HST_STA, status);
596                         wakeup(sc);
597                         break;
598                 }
599
600                 /* Clear status bits and try again */
601                 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, status);
602         }
603         crit_exit();
604
605         /* Too many loops? */
606         if (count == maxloops) {
607                 log(LOG_ERR, "%s: interrupt loop, status=0x%02x\n",
608                     device_get_nameunit(dev),
609                     bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA));
610         }
611 }
612
613 /*
614  * Wait for command completion. Assumes a critical section.
615  * Returns an SMB_* error code.
616  */
617 static int
618 ichsmb_wait(sc_p sc)
619 {
620         const device_t dev = sc->dev;
621         int error, smb_error;
622
623         KASSERT(sc->ich_cmd != -1,
624             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
625 sleep:
626         error = tsleep(sc, PCATCH, "ichsmb", hz / 4);
627         DBG("tsleep -> %d\n", error);
628         switch (error) {
629         case ERESTART:
630                 if (sc->ich_cmd != -1)
631                         goto sleep;
632                 /* FALLTHROUGH */
633         case 0:
634                 smb_error = sc->smb_error;
635                 break;
636         case EWOULDBLOCK:
637                 log(LOG_ERR, "%s: device timeout, status=0x%02x\n",
638                     device_get_nameunit(dev),
639                     bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA));
640                 sc->ich_cmd = -1;
641                 smb_error = SMB_ETIMEOUT;
642                 break;
643         default:
644                 smb_error = SMB_EABORT;
645                 break;
646         }
647         return (smb_error);
648 }
649
650 /*
651  * Release resources associated with device.
652  */
653 void
654 ichsmb_release_resources(sc_p sc)
655 {
656         const device_t dev = sc->dev;
657
658         if (sc->irq_handle != NULL) {
659                 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
660                 sc->irq_handle = NULL;
661         }
662         if (sc->irq_res != NULL) {
663                 bus_release_resource(dev,
664                     SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
665                 sc->irq_res = NULL;
666         }
667         if (sc->io_res != NULL) {
668                 bus_release_resource(dev,
669                     SYS_RES_IOPORT, sc->io_rid, sc->io_res);
670                 sc->io_res = NULL;
671         }
672 }
673