]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/intpm/intpm.c
THIS BRANCH IS OBSOLETE, PLEASE READ:
[FreeBSD/FreeBSD.git] / sys / dev / intpm / intpm.c
1 /*-
2  * Copyright (c) 1998, 1999 Takanori Watanabe
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *        notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *        notice, this list of conditions and the following disclaimer in the
12  *        documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/bus.h>
33 #include <sys/kernel.h>
34 #include <sys/lock.h>
35 #include <sys/module.h>
36 #include <sys/mutex.h>
37 #include <sys/rman.h>
38 #include <machine/bus.h>
39 #include <dev/smbus/smbconf.h>
40
41 #include "smbus_if.h"
42
43 #include <dev/pci/pcireg.h>
44 #include <dev/pci/pcivar.h>
45 #include <dev/intpm/intpmreg.h>
46 #include <dev/amdsbwd/amd_chipset.h>
47
48 #include "opt_intpm.h"
49
50 struct intsmb_softc {
51         device_t                dev;
52         struct resource         *io_res;
53         struct resource         *irq_res;
54         void                    *irq_hand;
55         device_t                smbus;
56         int                     io_rid;
57         int                     isbusy;
58         int                     cfg_irq9;
59         int                     sb8xx;
60         int                     poll;
61         struct mtx              lock;
62 };
63
64 #define INTSMB_LOCK(sc)         mtx_lock(&(sc)->lock)
65 #define INTSMB_UNLOCK(sc)       mtx_unlock(&(sc)->lock)
66 #define INTSMB_LOCK_ASSERT(sc)  mtx_assert(&(sc)->lock, MA_OWNED)
67
68 static int intsmb_probe(device_t);
69 static int intsmb_attach(device_t);
70 static int intsmb_detach(device_t);
71 static int intsmb_intr(struct intsmb_softc *sc);
72 static int intsmb_slvintr(struct intsmb_softc *sc);
73 static void intsmb_alrintr(struct intsmb_softc *sc);
74 static int intsmb_callback(device_t dev, int index, void *data);
75 static int intsmb_quick(device_t dev, u_char slave, int how);
76 static int intsmb_sendb(device_t dev, u_char slave, char byte);
77 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
78 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
79 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
80 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
81 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
82 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
83 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
84 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf);
85 static void intsmb_start(struct intsmb_softc *sc, u_char cmd, int nointr);
86 static int intsmb_stop(struct intsmb_softc *sc);
87 static int intsmb_stop_poll(struct intsmb_softc *sc);
88 static int intsmb_free(struct intsmb_softc *sc);
89 static void intsmb_rawintr(void *arg);
90
91 const struct intsmb_device {
92         uint32_t devid;
93         const char *description;
94 } intsmb_products[] = {
95         { 0x71138086, "Intel PIIX4 SMBUS Interface" },
96         { 0x719b8086, "Intel PIIX4 SMBUS Interface" },
97 #if 0
98         /* Not a good idea yet, this stops isab0 functioning */
99         { 0x02001166, "ServerWorks OSB4" },
100 #endif
101         { 0x43721002, "ATI IXP400 SMBus Controller" },
102         { AMDSB_SMBUS_DEVID, "AMD SB600/7xx/8xx/9xx SMBus Controller" },
103         { AMDFCH_SMBUS_DEVID, "AMD FCH SMBus Controller" },
104         { AMDCZ_SMBUS_DEVID, "AMD FCH SMBus Controller" },
105         { HYGONCZ_SMBUS_DEVID, "Hygon FCH SMBus Controller" },
106 };
107
108 static int
109 intsmb_probe(device_t dev)
110 {
111         const struct intsmb_device *isd;
112         uint32_t devid;
113         size_t i;
114
115         devid = pci_get_devid(dev);
116         for (i = 0; i < nitems(intsmb_products); i++) {
117                 isd = &intsmb_products[i];
118                 if (isd->devid == devid) {
119                         device_set_desc(dev, isd->description);
120                         return (BUS_PROBE_DEFAULT);
121                 }
122         }
123         return (ENXIO);
124 }
125
126 static uint8_t
127 amd_pmio_read(struct resource *res, uint8_t reg)
128 {
129         bus_write_1(res, 0, reg);       /* Index */
130         return (bus_read_1(res, 1));    /* Data */
131 }
132
133 static int
134 sb8xx_attach(device_t dev)
135 {
136         static const int        AMDSB_SMBIO_WIDTH = 0x10;
137         struct intsmb_softc     *sc;
138         struct resource         *res;
139         uint32_t                devid;
140         uint8_t                 revid;
141         uint16_t                addr;
142         int                     rid;
143         int                     rc;
144         bool                    enabled;
145
146         sc = device_get_softc(dev);
147         rid = 0;
148         rc = bus_set_resource(dev, SYS_RES_IOPORT, rid, AMDSB_PMIO_INDEX,
149             AMDSB_PMIO_WIDTH);
150         if (rc != 0) {
151                 device_printf(dev, "bus_set_resource for PM IO failed\n");
152                 return (ENXIO);
153         }
154         res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
155             RF_ACTIVE);
156         if (res == NULL) {
157                 device_printf(dev, "bus_alloc_resource for PM IO failed\n");
158                 return (ENXIO);
159         }
160
161         devid = pci_get_devid(dev);
162         revid = pci_get_revid(dev);
163         if (devid == AMDSB_SMBUS_DEVID ||
164             (devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) ||
165             (devid == AMDCZ_SMBUS_DEVID  && revid < AMDCZ49_SMBUS_REVID)) {
166                 addr = amd_pmio_read(res, AMDSB8_PM_SMBUS_EN + 1);
167                 addr <<= 8;
168                 addr |= amd_pmio_read(res, AMDSB8_PM_SMBUS_EN);
169                 enabled = (addr & AMDSB8_SMBUS_EN) != 0;
170                 addr &= AMDSB8_SMBUS_ADDR_MASK;
171         } else {
172                 addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN0);
173                 enabled = (addr & AMDFCH41_SMBUS_EN) != 0;
174                 addr = amd_pmio_read(res, AMDFCH41_PM_DECODE_EN1);
175                 addr <<= 8;
176         }
177
178         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
179         bus_delete_resource(dev, SYS_RES_IOPORT, rid);
180
181         if (!enabled) {
182                 device_printf(dev, "SB8xx/SB9xx/FCH SMBus not enabled\n");
183                 return (ENXIO);
184         }
185
186         sc->io_rid = 0;
187         rc = bus_set_resource(dev, SYS_RES_IOPORT, sc->io_rid, addr,
188             AMDSB_SMBIO_WIDTH);
189         if (rc != 0) {
190                 device_printf(dev, "bus_set_resource for SMBus IO failed\n");
191                 return (ENXIO);
192         }
193         sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
194             RF_ACTIVE);
195         if (sc->io_res == NULL) {
196                 device_printf(dev, "Could not allocate I/O space\n");
197                 return (ENXIO);
198         }
199         sc->poll = 1;
200         return (0);
201 }
202
203 static void
204 intsmb_release_resources(device_t dev)
205 {
206         struct intsmb_softc *sc = device_get_softc(dev);
207
208         if (sc->smbus)
209                 device_delete_child(dev, sc->smbus);
210         if (sc->irq_hand)
211                 bus_teardown_intr(dev, sc->irq_res, sc->irq_hand);
212         if (sc->irq_res)
213                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
214         if (sc->io_res)
215                 bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid,
216                     sc->io_res);
217         mtx_destroy(&sc->lock);
218 }
219
220 static int
221 intsmb_attach(device_t dev)
222 {
223         struct intsmb_softc *sc = device_get_softc(dev);
224         int error, rid, value;
225         int intr;
226         char *str;
227
228         sc->dev = dev;
229
230         mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF);
231
232         sc->cfg_irq9 = 0;
233         switch (pci_get_devid(dev)) {
234 #ifndef NO_CHANGE_PCICONF
235         case 0x71138086:        /* Intel 82371AB */
236         case 0x719b8086:        /* Intel 82443MX */
237                 /* Changing configuration is allowed. */
238                 sc->cfg_irq9 = 1;
239                 break;
240 #endif
241         case AMDSB_SMBUS_DEVID:
242                 if (pci_get_revid(dev) >= AMDSB8_SMBUS_REVID)
243                         sc->sb8xx = 1;
244                 break;
245         case AMDFCH_SMBUS_DEVID:
246         case AMDCZ_SMBUS_DEVID:
247         case HYGONCZ_SMBUS_DEVID:
248                 sc->sb8xx = 1;
249                 break;
250         }
251
252         if (sc->sb8xx) {
253                 error = sb8xx_attach(dev);
254                 if (error != 0)
255                         goto fail;
256                 else
257                         goto no_intr;
258         }
259
260         sc->io_rid = PCI_BASE_ADDR_SMB;
261         sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->io_rid,
262             RF_ACTIVE);
263         if (sc->io_res == NULL) {
264                 device_printf(dev, "Could not allocate I/O space\n");
265                 error = ENXIO;
266                 goto fail;
267         }
268
269         if (sc->cfg_irq9) {
270                 pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
271                 pci_write_config(dev, PCI_HST_CFG_SMB,
272                     PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
273         }
274         value = pci_read_config(dev, PCI_HST_CFG_SMB, 1);
275         sc->poll = (value & PCI_INTR_SMB_ENABLE) == 0;
276         intr = value & PCI_INTR_SMB_MASK;
277         switch (intr) {
278         case PCI_INTR_SMB_SMI:
279                 str = "SMI";
280                 break;
281         case PCI_INTR_SMB_IRQ9:
282                 str = "IRQ 9";
283                 break;
284         case PCI_INTR_SMB_IRQ_PCI:
285                 str = "PCI IRQ";
286                 break;
287         default:
288                 str = "BOGUS";
289         }
290
291         device_printf(dev, "intr %s %s ", str,
292             sc->poll == 0 ? "enabled" : "disabled");
293         printf("revision %d\n", pci_read_config(dev, PCI_REVID_SMB, 1));
294
295         if (!sc->poll && intr == PCI_INTR_SMB_SMI) {
296                 device_printf(dev,
297                     "using polling mode when configured interrupt is SMI\n");
298                 sc->poll = 1;
299         }
300
301         if (sc->poll)
302             goto no_intr;
303
304         if (intr != PCI_INTR_SMB_IRQ9 && intr != PCI_INTR_SMB_IRQ_PCI) {
305                 device_printf(dev, "Unsupported interrupt mode\n");
306                 error = ENXIO;
307                 goto fail;
308         }
309
310         /* Force IRQ 9. */
311         rid = 0;
312         if (sc->cfg_irq9)
313                 bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1);
314
315         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
316             RF_SHAREABLE | RF_ACTIVE);
317         if (sc->irq_res == NULL) {
318                 device_printf(dev, "Could not allocate irq\n");
319                 error = ENXIO;
320                 goto fail;
321         }
322
323         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
324             NULL, intsmb_rawintr, sc, &sc->irq_hand);
325         if (error) {
326                 device_printf(dev, "Failed to map intr\n");
327                 goto fail;
328         }
329
330 no_intr:
331         sc->isbusy = 0;
332         sc->smbus = device_add_child(dev, "smbus", -1);
333         if (sc->smbus == NULL) {
334                 device_printf(dev, "failed to add smbus child\n");
335                 error = ENXIO;
336                 goto fail;
337         }
338         error = device_probe_and_attach(sc->smbus);
339         if (error) {
340                 device_printf(dev, "failed to probe+attach smbus child\n");
341                 goto fail;
342         }
343
344 #ifdef ENABLE_ALART
345         /* Enable Arart */
346         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN);
347 #endif
348         return (0);
349
350 fail:
351         intsmb_release_resources(dev);
352         return (error);
353 }
354
355 static int
356 intsmb_detach(device_t dev)
357 {
358         int error;
359
360         error = bus_generic_detach(dev);
361         if (error) {
362                 device_printf(dev, "bus detach failed\n");
363                 return (error);
364         }
365
366         intsmb_release_resources(dev);
367         return (0);
368 }
369
370 static void
371 intsmb_rawintr(void *arg)
372 {
373         struct intsmb_softc *sc = arg;
374
375         INTSMB_LOCK(sc);
376         intsmb_intr(sc);
377         intsmb_slvintr(sc);
378         INTSMB_UNLOCK(sc);
379 }
380
381 static int
382 intsmb_callback(device_t dev, int index, void *data)
383 {
384         int error = 0;
385
386         switch (index) {
387         case SMB_REQUEST_BUS:
388                 break;
389         case SMB_RELEASE_BUS:
390                 break;
391         default:
392                 error = SMB_EINVAL;
393         }
394
395         return (error);
396 }
397
398 /* Counterpart of smbtx_smb_free(). */
399 static int
400 intsmb_free(struct intsmb_softc *sc)
401 {
402
403         INTSMB_LOCK_ASSERT(sc);
404         if ((bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & PIIX4_SMBHSTSTAT_BUSY) ||
405 #ifdef ENABLE_ALART
406             (bus_read_1(sc->io_res, PIIX4_SMBSLVSTS) & PIIX4_SMBSLVSTS_BUSY) ||
407 #endif
408             sc->isbusy)
409                 return (SMB_EBUSY);
410
411         sc->isbusy = 1;
412         /* Disable Interrupt in slave part. */
413 #ifndef ENABLE_ALART
414         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 0);
415 #endif
416         /* Reset INTR Flag to prepare INTR. */
417         bus_write_1(sc->io_res, PIIX4_SMBHSTSTS,
418             PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
419             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL);
420         return (0);
421 }
422
423 static int
424 intsmb_intr(struct intsmb_softc *sc)
425 {
426         int status, tmp;
427
428         status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
429         if (status & PIIX4_SMBHSTSTAT_BUSY)
430                 return (1);
431
432         if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
433             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) {
434
435                 tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
436                 bus_write_1(sc->io_res, PIIX4_SMBHSTCNT,
437                     tmp & ~PIIX4_SMBHSTCNT_INTREN);
438                 if (sc->isbusy) {
439                         sc->isbusy = 0;
440                         wakeup(sc);
441                 }
442                 return (0);
443         }
444         return (1); /* Not Completed */
445 }
446
447 static int
448 intsmb_slvintr(struct intsmb_softc *sc)
449 {
450         int status;
451
452         status = bus_read_1(sc->io_res, PIIX4_SMBSLVSTS);
453         if (status & PIIX4_SMBSLVSTS_BUSY)
454                 return (1);
455         if (status & PIIX4_SMBSLVSTS_ALART)
456                 intsmb_alrintr(sc);
457         else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2
458                 | PIIX4_SMBSLVSTS_SDW1)) {
459         }
460
461         /* Reset Status Register */
462         bus_write_1(sc->io_res, PIIX4_SMBSLVSTS,
463             PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 |
464             PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV);
465         return (0);
466 }
467
468 static void
469 intsmb_alrintr(struct intsmb_softc *sc)
470 {
471         int slvcnt;
472 #ifdef ENABLE_ALART
473         int error;
474         uint8_t addr;
475 #endif
476
477         /* Stop generating INTR from ALART. */
478         slvcnt = bus_read_1(sc->io_res, PIIX4_SMBSLVCNT);
479 #ifdef ENABLE_ALART
480         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
481             slvcnt & ~PIIX4_SMBSLVCNT_ALTEN);
482 #endif
483         DELAY(5);
484
485         /* Ask bus who asserted it and then ask it what's the matter. */
486 #ifdef ENABLE_ALART
487         error = intsmb_free(sc);
488         if (error)
489                 return;
490
491         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, SMBALTRESP | LSB);
492         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 1);
493         error = intsmb_stop_poll(sc);
494         if (error)
495                 device_printf(sc->dev, "ALART: ERROR\n");
496         else {
497                 addr = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
498                 device_printf(sc->dev, "ALART_RESPONSE: 0x%x\n", addr);
499         }
500
501         /* Re-enable INTR from ALART. */
502         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
503             slvcnt | PIIX4_SMBSLVCNT_ALTEN);
504         DELAY(5);
505 #endif
506 }
507
508 static void
509 intsmb_start(struct intsmb_softc *sc, unsigned char cmd, int nointr)
510 {
511         unsigned char tmp;
512
513         INTSMB_LOCK_ASSERT(sc);
514         tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
515         tmp &= 0xe0;
516         tmp |= cmd;
517         tmp |= PIIX4_SMBHSTCNT_START;
518
519         /* While not in autoconfiguration enable interrupts. */
520         if (!sc->poll && !cold && !nointr)
521                 tmp |= PIIX4_SMBHSTCNT_INTREN;
522         bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp);
523 }
524
525 static int
526 intsmb_error(device_t dev, int status)
527 {
528         int error = 0;
529
530         /*
531          * PIIX4_SMBHSTSTAT_ERR can mean either of
532          * - SMB_ENOACK ("Unclaimed cycle"),
533          * - SMB_ETIMEOUT ("Host device time-out"),
534          * - SMB_EINVAL ("Illegal command field").
535          * SMB_ENOACK seems to be most typical.
536          */
537         if (status & PIIX4_SMBHSTSTAT_ERR)
538                 error |= SMB_ENOACK;
539         if (status & PIIX4_SMBHSTSTAT_BUSC)
540                 error |= SMB_ECOLLI;
541         if (status & PIIX4_SMBHSTSTAT_FAIL)
542                 error |= SMB_EABORT;
543
544         if (error != 0 && bootverbose)
545                 device_printf(dev, "error = %d, status = %#x\n", error, status);
546
547         return (error);
548 }
549
550 /*
551  * Polling Code.
552  *
553  * Polling is not encouraged because it requires waiting for the
554  * device if it is busy.
555  * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use
556  * polling code then.
557  */
558 static int
559 intsmb_stop_poll(struct intsmb_softc *sc)
560 {
561         int error, i, status, tmp;
562
563         INTSMB_LOCK_ASSERT(sc);
564
565         /* First, wait for busy to be set. */
566         for (i = 0; i < 0x7fff; i++)
567                 if (bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) &
568                     PIIX4_SMBHSTSTAT_BUSY)
569                         break;
570
571         /* Wait for busy to clear. */
572         for (i = 0; i < 0x7fff; i++) {
573                 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
574                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
575                         sc->isbusy = 0;
576                         error = intsmb_error(sc->dev, status);
577                         return (error);
578                 }
579         }
580
581         /* Timed out waiting for busy to clear. */
582         sc->isbusy = 0;
583         tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
584         bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp & ~PIIX4_SMBHSTCNT_INTREN);
585         return (SMB_ETIMEOUT);
586 }
587
588 /*
589  * Wait for completion and return result.
590  */
591 static int
592 intsmb_stop(struct intsmb_softc *sc)
593 {
594         int error, status;
595
596         INTSMB_LOCK_ASSERT(sc);
597
598         if (sc->poll || cold)
599                 /* So that it can use device during device probe on SMBus. */
600                 return (intsmb_stop_poll(sc));
601
602         error = msleep(sc, &sc->lock, PWAIT | PCATCH, "SMBWAI", hz / 8);
603         if (error == 0) {
604                 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
605                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
606                         error = intsmb_error(sc->dev, status);
607                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
608                                 device_printf(sc->dev, "unknown cause why?\n");
609 #ifdef ENABLE_ALART
610                         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
611                             PIIX4_SMBSLVCNT_ALTEN);
612 #endif
613                         return (error);
614                 }
615         }
616
617         /* Timeout Procedure. */
618         sc->isbusy = 0;
619
620         /* Re-enable suppressed interrupt from slave part. */
621         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN);
622         if (error == EWOULDBLOCK)
623                 return (SMB_ETIMEOUT);
624         else
625                 return (SMB_EABORT);
626 }
627
628 static int
629 intsmb_quick(device_t dev, u_char slave, int how)
630 {
631         struct intsmb_softc *sc = device_get_softc(dev);
632         int error;
633         u_char data;
634
635         data = slave;
636
637         /* Quick command is part of Address, I think. */
638         switch(how) {
639         case SMB_QWRITE:
640                 data &= ~LSB;
641                 break;
642         case SMB_QREAD:
643                 data |= LSB;
644                 break;
645         default:
646                 return (SMB_EINVAL);
647         }
648
649         INTSMB_LOCK(sc);
650         error = intsmb_free(sc);
651         if (error) {
652                 INTSMB_UNLOCK(sc);
653                 return (error);
654         }
655         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, data);
656         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_QUICK, 0);
657         error = intsmb_stop(sc);
658         INTSMB_UNLOCK(sc);
659         return (error);
660 }
661
662 static int
663 intsmb_sendb(device_t dev, u_char slave, char byte)
664 {
665         struct intsmb_softc *sc = device_get_softc(dev);
666         int error;
667
668         INTSMB_LOCK(sc);
669         error = intsmb_free(sc);
670         if (error) {
671                 INTSMB_UNLOCK(sc);
672                 return (error);
673         }
674         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
675         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, byte);
676         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
677         error = intsmb_stop(sc);
678         INTSMB_UNLOCK(sc);
679         return (error);
680 }
681
682 static int
683 intsmb_recvb(device_t dev, u_char slave, char *byte)
684 {
685         struct intsmb_softc *sc = device_get_softc(dev);
686         int error;
687
688         INTSMB_LOCK(sc);
689         error = intsmb_free(sc);
690         if (error) {
691                 INTSMB_UNLOCK(sc);
692                 return (error);
693         }
694         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
695         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
696         error = intsmb_stop(sc);
697         if (error == 0) {
698 #ifdef RECV_IS_IN_CMD
699                 /*
700                  * Linux SMBus stuff also troubles
701                  * Because Intel's datasheet does not make clear.
702                  */
703                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTCMD);
704 #else
705                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
706 #endif
707         }
708         INTSMB_UNLOCK(sc);
709         return (error);
710 }
711
712 static int
713 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
714 {
715         struct intsmb_softc *sc = device_get_softc(dev);
716         int error;
717
718         INTSMB_LOCK(sc);
719         error = intsmb_free(sc);
720         if (error) {
721                 INTSMB_UNLOCK(sc);
722                 return (error);
723         }
724         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
725         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
726         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, byte);
727         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
728         error = intsmb_stop(sc);
729         INTSMB_UNLOCK(sc);
730         return (error);
731 }
732
733 static int
734 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
735 {
736         struct intsmb_softc *sc = device_get_softc(dev);
737         int error;
738
739         INTSMB_LOCK(sc);
740         error = intsmb_free(sc);
741         if (error) {
742                 INTSMB_UNLOCK(sc);
743                 return (error);
744         }
745         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
746         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
747         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, word & 0xff);
748         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (word >> 8) & 0xff);
749         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
750         error = intsmb_stop(sc);
751         INTSMB_UNLOCK(sc);
752         return (error);
753 }
754
755 static int
756 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
757 {
758         struct intsmb_softc *sc = device_get_softc(dev);
759         int error;
760
761         INTSMB_LOCK(sc);
762         error = intsmb_free(sc);
763         if (error) {
764                 INTSMB_UNLOCK(sc);
765                 return (error);
766         }
767         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
768         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
769         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
770         error = intsmb_stop(sc);
771         if (error == 0)
772                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
773         INTSMB_UNLOCK(sc);
774         return (error);
775 }
776
777 static int
778 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
779 {
780         struct intsmb_softc *sc = device_get_softc(dev);
781         int error;
782
783         INTSMB_LOCK(sc);
784         error = intsmb_free(sc);
785         if (error) {
786                 INTSMB_UNLOCK(sc);
787                 return (error);
788         }
789         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
790         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
791         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
792         error = intsmb_stop(sc);
793         if (error == 0) {
794                 *word = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
795                 *word |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8;
796         }
797         INTSMB_UNLOCK(sc);
798         return (error);
799 }
800
801 static int
802 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
803 {
804
805         return (SMB_ENOTSUPP);
806 }
807
808 static int
809 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
810 {
811         struct intsmb_softc *sc = device_get_softc(dev);
812         int error, i;
813
814         if (count > SMBBLOCKTRANS_MAX || count == 0)
815                 return (SMB_EINVAL);
816
817         INTSMB_LOCK(sc);
818         error = intsmb_free(sc);
819         if (error) {
820                 INTSMB_UNLOCK(sc);
821                 return (error);
822         }
823
824         /* Reset internal array index. */
825         bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
826
827         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
828         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
829         for (i = 0; i < count; i++)
830                 bus_write_1(sc->io_res, PIIX4_SMBBLKDAT, buf[i]);
831         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, count);
832         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
833         error = intsmb_stop(sc);
834         INTSMB_UNLOCK(sc);
835         return (error);
836 }
837
838 static int
839 intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
840 {
841         struct intsmb_softc *sc = device_get_softc(dev);
842         int error, i;
843         u_char data, nread;
844
845         INTSMB_LOCK(sc);
846         error = intsmb_free(sc);
847         if (error) {
848                 INTSMB_UNLOCK(sc);
849                 return (error);
850         }
851
852         /* Reset internal array index. */
853         bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
854
855         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
856         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
857         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
858         error = intsmb_stop(sc);
859         if (error == 0) {
860                 nread = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
861                 if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) {
862                         *count = nread;
863                         for (i = 0; i < nread; i++)
864                                 data = bus_read_1(sc->io_res, PIIX4_SMBBLKDAT);
865                 } else
866                         error = SMB_EBUSERR;
867         }
868         INTSMB_UNLOCK(sc);
869         return (error);
870 }
871
872 static devclass_t intsmb_devclass;
873
874 static device_method_t intsmb_methods[] = {
875         /* Device interface */
876         DEVMETHOD(device_probe,         intsmb_probe),
877         DEVMETHOD(device_attach,        intsmb_attach),
878         DEVMETHOD(device_detach,        intsmb_detach),
879
880         /* SMBus interface */
881         DEVMETHOD(smbus_callback,       intsmb_callback),
882         DEVMETHOD(smbus_quick,          intsmb_quick),
883         DEVMETHOD(smbus_sendb,          intsmb_sendb),
884         DEVMETHOD(smbus_recvb,          intsmb_recvb),
885         DEVMETHOD(smbus_writeb,         intsmb_writeb),
886         DEVMETHOD(smbus_writew,         intsmb_writew),
887         DEVMETHOD(smbus_readb,          intsmb_readb),
888         DEVMETHOD(smbus_readw,          intsmb_readw),
889         DEVMETHOD(smbus_pcall,          intsmb_pcall),
890         DEVMETHOD(smbus_bwrite,         intsmb_bwrite),
891         DEVMETHOD(smbus_bread,          intsmb_bread),
892
893         DEVMETHOD_END
894 };
895
896 static driver_t intsmb_driver = {
897         "intsmb",
898         intsmb_methods,
899         sizeof(struct intsmb_softc),
900 };
901
902 DRIVER_MODULE_ORDERED(intsmb, pci, intsmb_driver, intsmb_devclass, 0, 0,
903     SI_ORDER_ANY);
904 DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0);
905 MODULE_DEPEND(intsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
906 MODULE_VERSION(intsmb, 1);
907 MODULE_PNP_INFO("W32:vendor/device;D:#", pci, intpm, intsmb_products,
908     nitems(intsmb_products));