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