1 /*-
2 * ichsmb.c
3 *
4 * Author: Archie Cobbs <archie@freebsd.org>
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
38 #include <sys/cdefs.h>
39 /*
40 * Support for the SMBus controller logical device which is part of the
41 * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips.
42 *
43 * This driver assumes that the generic SMBus code will ensure that
44 * at most one process at a time calls into the SMBus methods below.
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/kernel.h>
50 #include <sys/errno.h>
51 #include <sys/lock.h>
52 #include <sys/module.h>
53 #include <sys/mutex.h>
54 #include <sys/syslog.h>
55 #include <sys/bus.h>
56
57 #include <machine/bus.h>
58 #include <sys/rman.h>
59 #include <machine/resource.h>
60
61 #include <dev/smbus/smbconf.h>
62
63 #include <dev/ichsmb/ichsmb_var.h>
64 #include <dev/ichsmb/ichsmb_reg.h>
65
66 /*
67 * Enable debugging by defining ICHSMB_DEBUG to a non-zero value.
68 */
69 #define ICHSMB_DEBUG 0
70 #if ICHSMB_DEBUG != 0
71 #define DBG(fmt, args...) \
72 do { printf("%s: " fmt, __func__ , ## args); } while (0)
73 #else
74 #define DBG(fmt, args...) do { } while (0)
75 #endif
76
77 /*
78 * Our child device driver name
79 */
80 #define DRIVER_SMBUS "smbus"
81
82 /*
83 * Internal functions
84 */
85 static int ichsmb_wait(sc_p sc);
86
87 /********************************************************************
88 BUS-INDEPENDENT BUS METHODS
89 ********************************************************************/
90
91 /*
92 * Handle probe-time duties that are independent of the bus
93 * our device lives on.
94 */
95 int
ichsmb_probe(device_t dev)96 ichsmb_probe(device_t dev)
97 {
98 return (BUS_PROBE_DEFAULT);
99 }
100
101 /*
102 * Handle attach-time duties that are independent of the bus
103 * our device lives on.
104 */
105 int
ichsmb_attach(device_t dev)106 ichsmb_attach(device_t dev)
107 {
108 const sc_p sc = device_get_softc(dev);
109 int error;
110
111 /* Create mutex */
112 mtx_init(&sc->mutex, device_get_nameunit(dev), "ichsmb", MTX_DEF);
113
114 /* Add child: an instance of the "smbus" device */
115 if ((sc->smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) {
116 device_printf(dev, "no \"%s\" child found\n", DRIVER_SMBUS);
117 error = ENXIO;
118 goto fail;
119 }
120
121 /* Clear interrupt conditions */
122 bus_write_1(sc->io_res, ICH_HST_STA, 0xff);
123
124 /* Set up interrupt handler */
125 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
126 NULL, ichsmb_device_intr, sc, &sc->irq_handle);
127 if (error != 0) {
128 device_printf(dev, "can't setup irq\n");
129 goto fail;
130 }
131
132 /* Attach children when interrupts are available */
133 bus_delayed_attach_children(dev);
134 return (0);
135 fail:
136 mtx_destroy(&sc->mutex);
137 return (error);
138 }
139
140 /********************************************************************
141 SMBUS METHODS
142 ********************************************************************/
143
144 int
ichsmb_callback(device_t dev,int index,void * data)145 ichsmb_callback(device_t dev, int index, void *data)
146 {
147 int smb_error = 0;
148
149 DBG("index=%d how=%d\n", index, data ? *(int *)data : -1);
150 switch (index) {
151 case SMB_REQUEST_BUS:
152 break;
153 case SMB_RELEASE_BUS:
154 break;
155 default:
156 smb_error = SMB_EABORT; /* XXX */
157 break;
158 }
159 DBG("smb_error=%d\n", smb_error);
160 return (smb_error);
161 }
162
163 int
ichsmb_quick(device_t dev,u_char slave,int how)164 ichsmb_quick(device_t dev, u_char slave, int how)
165 {
166 const sc_p sc = device_get_softc(dev);
167 int smb_error;
168
169 DBG("slave=0x%02x how=%d\n", slave, how);
170 KASSERT(sc->ich_cmd == -1,
171 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
172 switch (how) {
173 case SMB_QREAD:
174 case SMB_QWRITE:
175 mtx_lock(&sc->mutex);
176 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK;
177 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
178 slave | (how == SMB_QREAD ?
179 ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE));
180 bus_write_1(sc->io_res, ICH_HST_CNT,
181 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
182 smb_error = ichsmb_wait(sc);
183 mtx_unlock(&sc->mutex);
184 break;
185 default:
186 smb_error = SMB_ENOTSUPP;
187 }
188 DBG("smb_error=%d\n", smb_error);
189 return (smb_error);
190 }
191
192 int
ichsmb_sendb(device_t dev,u_char slave,char byte)193 ichsmb_sendb(device_t dev, u_char slave, char byte)
194 {
195 const sc_p sc = device_get_softc(dev);
196 int smb_error;
197
198 DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte);
199 KASSERT(sc->ich_cmd == -1,
200 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
201 mtx_lock(&sc->mutex);
202 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
203 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
204 slave | ICH_XMIT_SLVA_WRITE);
205 bus_write_1(sc->io_res, ICH_HST_CMD, byte);
206 bus_write_1(sc->io_res, ICH_HST_CNT,
207 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
208 smb_error = ichsmb_wait(sc);
209 mtx_unlock(&sc->mutex);
210 DBG("smb_error=%d\n", smb_error);
211 return (smb_error);
212 }
213
214 int
ichsmb_recvb(device_t dev,u_char slave,char * byte)215 ichsmb_recvb(device_t dev, u_char slave, char *byte)
216 {
217 const sc_p sc = device_get_softc(dev);
218 int smb_error;
219
220 DBG("slave=0x%02x\n", slave);
221 KASSERT(sc->ich_cmd == -1,
222 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
223 mtx_lock(&sc->mutex);
224 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
225 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
226 slave | ICH_XMIT_SLVA_READ);
227 bus_write_1(sc->io_res, ICH_HST_CNT,
228 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
229 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
230 *byte = bus_read_1(sc->io_res, ICH_D0);
231 mtx_unlock(&sc->mutex);
232 DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
233 return (smb_error);
234 }
235
236 int
ichsmb_writeb(device_t dev,u_char slave,char cmd,char byte)237 ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
238 {
239 const sc_p sc = device_get_softc(dev);
240 int smb_error;
241
242 DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n",
243 slave, (u_char)cmd, (u_char)byte);
244 KASSERT(sc->ich_cmd == -1,
245 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
246 mtx_lock(&sc->mutex);
247 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
248 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
249 slave | ICH_XMIT_SLVA_WRITE);
250 bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
251 bus_write_1(sc->io_res, ICH_D0, byte);
252 bus_write_1(sc->io_res, ICH_HST_CNT,
253 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
254 smb_error = ichsmb_wait(sc);
255 mtx_unlock(&sc->mutex);
256 DBG("smb_error=%d\n", smb_error);
257 return (smb_error);
258 }
259
260 int
ichsmb_writew(device_t dev,u_char slave,char cmd,short word)261 ichsmb_writew(device_t dev, u_char slave, char cmd, short word)
262 {
263 const sc_p sc = device_get_softc(dev);
264 int smb_error;
265
266 DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n",
267 slave, (u_char)cmd, (u_int16_t)word);
268 KASSERT(sc->ich_cmd == -1,
269 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
270 mtx_lock(&sc->mutex);
271 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
272 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
273 slave | ICH_XMIT_SLVA_WRITE);
274 bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
275 bus_write_1(sc->io_res, ICH_D0, word & 0xff);
276 bus_write_1(sc->io_res, ICH_D1, word >> 8);
277 bus_write_1(sc->io_res, ICH_HST_CNT,
278 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
279 smb_error = ichsmb_wait(sc);
280 mtx_unlock(&sc->mutex);
281 DBG("smb_error=%d\n", smb_error);
282 return (smb_error);
283 }
284
285 int
ichsmb_readb(device_t dev,u_char slave,char cmd,char * byte)286 ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
287 {
288 const sc_p sc = device_get_softc(dev);
289 int smb_error;
290
291 DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
292 KASSERT(sc->ich_cmd == -1,
293 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
294 mtx_lock(&sc->mutex);
295 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
296 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
297 slave | ICH_XMIT_SLVA_READ);
298 bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
299 bus_write_1(sc->io_res, ICH_HST_CNT,
300 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
301 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
302 *byte = bus_read_1(sc->io_res, ICH_D0);
303 mtx_unlock(&sc->mutex);
304 DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
305 return (smb_error);
306 }
307
308 int
ichsmb_readw(device_t dev,u_char slave,char cmd,short * word)309 ichsmb_readw(device_t dev, u_char slave, char cmd, short *word)
310 {
311 const sc_p sc = device_get_softc(dev);
312 int smb_error;
313
314 DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
315 KASSERT(sc->ich_cmd == -1,
316 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
317 mtx_lock(&sc->mutex);
318 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
319 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
320 slave | ICH_XMIT_SLVA_READ);
321 bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
322 bus_write_1(sc->io_res, ICH_HST_CNT,
323 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
324 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
325 *word = (bus_read_1(sc->io_res,
326 ICH_D0) & 0xff)
327 | (bus_read_1(sc->io_res,
328 ICH_D1) << 8);
329 }
330 mtx_unlock(&sc->mutex);
331 DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word);
332 return (smb_error);
333 }
334
335 int
ichsmb_pcall(device_t dev,u_char slave,char cmd,short sdata,short * rdata)336 ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
337 {
338 const sc_p sc = device_get_softc(dev);
339 int smb_error;
340
341 DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n",
342 slave, (u_char)cmd, (u_int16_t)sdata);
343 KASSERT(sc->ich_cmd == -1,
344 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
345 mtx_lock(&sc->mutex);
346 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL;
347 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
348 slave | ICH_XMIT_SLVA_WRITE);
349 bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
350 bus_write_1(sc->io_res, ICH_D0, sdata & 0xff);
351 bus_write_1(sc->io_res, ICH_D1, sdata >> 8);
352 bus_write_1(sc->io_res, ICH_HST_CNT,
353 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
354 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
355 *rdata = (bus_read_1(sc->io_res,
356 ICH_D0) & 0xff)
357 | (bus_read_1(sc->io_res,
358 ICH_D1) << 8);
359 }
360 mtx_unlock(&sc->mutex);
361 DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata);
362 return (smb_error);
363 }
364
365 int
ichsmb_bwrite(device_t dev,u_char slave,char cmd,u_char count,char * buf)366 ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
367 {
368 const sc_p sc = device_get_softc(dev);
369 int smb_error;
370
371 DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
372 #if ICHSMB_DEBUG
373 #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
374 {
375 u_char *p;
376
377 for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
378 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
379 " %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
380 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
381 DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]),
382 DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
383 }
384 }
385 #undef DISP
386 #endif
387 KASSERT(sc->ich_cmd == -1,
388 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
389 if (count < 1 || count > 32)
390 return (SMB_EINVAL);
391 bcopy(buf, sc->block_data, count);
392 sc->block_count = count;
393 sc->block_index = 1; /* buf[0] is written here */
394 sc->block_write = true;
395
396 mtx_lock(&sc->mutex);
397 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
398 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
399 slave | ICH_XMIT_SLVA_WRITE);
400 bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
401 bus_write_1(sc->io_res, ICH_D0, count);
402 bus_write_1(sc->io_res, ICH_BLOCK_DB, buf[0]);
403 bus_write_1(sc->io_res, ICH_HST_CNT,
404 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
405 smb_error = ichsmb_wait(sc);
406 mtx_unlock(&sc->mutex);
407 DBG("smb_error=%d\n", smb_error);
408 return (smb_error);
409 }
410
411 int
ichsmb_bread(device_t dev,u_char slave,char cmd,u_char * count,char * buf)412 ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
413 {
414 const sc_p sc = device_get_softc(dev);
415 int smb_error;
416
417 DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
418 KASSERT(sc->ich_cmd == -1,
419 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
420 bzero(sc->block_data, sizeof(sc->block_data));
421 sc->block_count = 0;
422 sc->block_index = 0;
423 sc->block_write = false;
424
425 mtx_lock(&sc->mutex);
426 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
427 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
428 slave | ICH_XMIT_SLVA_READ);
429 bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
430 bus_write_1(sc->io_res, ICH_HST_CNT,
431 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
432 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
433 bcopy(sc->block_data, buf, sc->block_count);
434 *count = sc->block_count;
435 }
436 mtx_unlock(&sc->mutex);
437 DBG("smb_error=%d\n", smb_error);
438 #if ICHSMB_DEBUG
439 #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
440 {
441 u_char *p;
442
443 for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
444 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
445 " %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
446 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
447 DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]),
448 DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
449 }
450 }
451 #undef DISP
452 #endif
453 return (smb_error);
454 }
455
456 /********************************************************************
457 OTHER FUNCTIONS
458 ********************************************************************/
459
460 /*
461 * This table describes what interrupts we should ever expect to
462 * see after each ICH command, not including the SMBALERT interrupt.
463 */
464 static const u_int8_t ichsmb_state_irqs[] = {
465 /* quick */
466 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
467 /* byte */
468 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
469 /* byte data */
470 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
471 /* word data */
472 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
473 /* process call */
474 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
475 /* block */
476 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
477 | ICH_HST_STA_BYTE_DONE_STS),
478 /* i2c read (not used) */
479 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
480 | ICH_HST_STA_BYTE_DONE_STS)
481 };
482
483 /*
484 * Interrupt handler. This handler is bus-independent. Note that our
485 * interrupt may be shared, so we must handle "false" interrupts.
486 */
487 void
ichsmb_device_intr(void * cookie)488 ichsmb_device_intr(void *cookie)
489 {
490 const sc_p sc = cookie;
491 const device_t dev = sc->dev;
492 const int maxloops = 16;
493 u_int8_t status;
494 u_int8_t ok_bits;
495 int cmd_index;
496 int count;
497
498 mtx_lock(&sc->mutex);
499 for (count = 0; count < maxloops; count++) {
500
501 /* Get and reset status bits */
502 status = bus_read_1(sc->io_res, ICH_HST_STA);
503 #if ICHSMB_DEBUG
504 if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY))
505 || count > 0) {
506 DBG("%d stat=0x%02x\n", count, status);
507 }
508 #endif
509 status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY |
510 ICH_HST_STA_SMBALERT_STS);
511 if (status == 0)
512 break;
513
514 /* Check for unexpected interrupt */
515 ok_bits = ICH_HST_STA_SMBALERT_STS;
516
517 if (sc->killed) {
518 sc->killed = 0;
519 ok_bits |= ICH_HST_STA_FAILED;
520 bus_write_1(sc->io_res, ICH_HST_CNT,
521 ICH_HST_CNT_INTREN);
522 }
523
524 if (sc->ich_cmd != -1) {
525 cmd_index = sc->ich_cmd >> 2;
526 KASSERT(cmd_index < sizeof(ichsmb_state_irqs),
527 ("%s: ich_cmd=%d", device_get_nameunit(dev),
528 sc->ich_cmd));
529 ok_bits |= ichsmb_state_irqs[cmd_index];
530 }
531 if ((status & ~ok_bits) != 0) {
532 device_printf(dev, "irq 0x%02x during 0x%02x\n", status,
533 sc->ich_cmd);
534 bus_write_1(sc->io_res,
535 ICH_HST_STA, (status & ~ok_bits));
536 continue;
537 }
538
539 /* Check for killed / aborted command */
540 if (status & ICH_HST_STA_FAILED) {
541 sc->smb_error = SMB_EABORT;
542 goto finished;
543 }
544
545 /* Check for bus error */
546 if (status & ICH_HST_STA_BUS_ERR) {
547 sc->smb_error = SMB_ECOLLI; /* XXX SMB_EBUSERR? */
548 goto finished;
549 }
550
551 /* Check for device error */
552 if (status & ICH_HST_STA_DEV_ERR) {
553 sc->smb_error = SMB_ENOACK; /* or SMB_ETIMEOUT? */
554 goto finished;
555 }
556
557 /* Check for byte completion in block transfer */
558 if (status & ICH_HST_STA_BYTE_DONE_STS) {
559 if (sc->block_write) {
560 if (sc->block_index < sc->block_count) {
561
562 /* Write next byte */
563 bus_write_1(sc->io_res,
564 ICH_BLOCK_DB,
565 sc->block_data[sc->block_index++]);
566 }
567 } else {
568
569 /* First interrupt, get the count also */
570 if (sc->block_index == 0) {
571 sc->block_count = bus_read_1(
572 sc->io_res, ICH_D0);
573 if (sc->block_count < 1 ||
574 sc->block_count > 32) {
575 device_printf(dev, "block read "
576 "wrong length: %d\n",
577 sc->block_count);
578 bus_write_1(sc->io_res,
579 ICH_HST_CNT,
580 ICH_HST_CNT_KILL |
581 ICH_HST_CNT_INTREN);
582 sc->block_count = 0;
583 sc->killed = true;
584 }
585 }
586
587 /* Get next byte, if any */
588 if (sc->block_index < sc->block_count) {
589
590 /* Read next byte */
591 sc->block_data[sc->block_index++] =
592 bus_read_1(sc->io_res,
593 ICH_BLOCK_DB);
594
595 /*
596 * Set "LAST_BYTE" bit before reading
597 * the last byte of block data
598 */
599 if (sc->block_index ==
600 sc->block_count - 1) {
601 bus_write_1(sc->io_res,
602 ICH_HST_CNT,
603 ICH_HST_CNT_LAST_BYTE |
604 ICH_HST_CNT_INTREN |
605 sc->ich_cmd);
606 }
607 }
608 }
609 }
610
611 /* Check command completion */
612 if (status & ICH_HST_STA_INTR) {
613 sc->smb_error = SMB_ENOERR;
614 finished:
615 sc->ich_cmd = -1;
616 bus_write_1(sc->io_res,
617 ICH_HST_STA, status);
618 wakeup(sc);
619 break;
620 }
621
622 /* Clear status bits and try again */
623 bus_write_1(sc->io_res, ICH_HST_STA, status);
624 }
625 mtx_unlock(&sc->mutex);
626
627 /* Too many loops? */
628 if (count == maxloops) {
629 device_printf(dev, "interrupt loop, status=0x%02x\n",
630 bus_read_1(sc->io_res, ICH_HST_STA));
631 }
632 }
633
634 /*
635 * Wait for command completion. Assumes mutex is held.
636 * Returns an SMB_* error code.
637 */
638 static int
ichsmb_wait(sc_p sc)639 ichsmb_wait(sc_p sc)
640 {
641 const device_t dev = sc->dev;
642 int error, smb_error;
643
644 KASSERT(sc->ich_cmd != -1,
645 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
646 mtx_assert(&sc->mutex, MA_OWNED);
647 error = msleep(sc, &sc->mutex, PZERO, "ichsmb", hz / 4);
648 DBG("msleep -> %d\n", error);
649 switch (error) {
650 case 0:
651 smb_error = sc->smb_error;
652 break;
653 case EWOULDBLOCK:
654 device_printf(dev, "device timeout, status=0x%02x\n",
655 bus_read_1(sc->io_res, ICH_HST_STA));
656 sc->ich_cmd = -1;
657 smb_error = SMB_ETIMEOUT;
658 break;
659 default:
660 smb_error = SMB_EABORT;
661 break;
662 }
663 return (smb_error);
664 }
665
666 /*
667 * Release resources associated with device.
668 */
669 void
ichsmb_release_resources(sc_p sc)670 ichsmb_release_resources(sc_p sc)
671 {
672 const device_t dev = sc->dev;
673
674 if (sc->irq_handle != NULL) {
675 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
676 sc->irq_handle = NULL;
677 }
678 if (sc->irq_res != NULL) {
679 bus_release_resource(dev,
680 SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
681 sc->irq_res = NULL;
682 }
683 if (sc->io_res != NULL) {
684 bus_release_resource(dev,
685 SYS_RES_IOPORT, sc->io_rid, sc->io_res);
686 sc->io_res = NULL;
687 }
688 }
689
690 int
ichsmb_detach(device_t dev)691 ichsmb_detach(device_t dev)
692 {
693 const sc_p sc = device_get_softc(dev);
694 int error;
695
696 error = bus_generic_detach(dev);
697 if (error)
698 return (error);
699 ichsmb_release_resources(sc);
700 mtx_destroy(&sc->mutex);
701
702 return 0;
703 }
704
705 DRIVER_MODULE(smbus, ichsmb, smbus_driver, 0, 0);
706