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