]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/pci/intpm.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / sys / pci / 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/kernel.h>
33 #include <machine/bus.h>
34
35 #include <sys/uio.h>
36 #include <sys/module.h>
37 #include <sys/bus.h>
38 #include <sys/rman.h>
39 #include <machine/resource.h>
40 #include <dev/smbus/smbconf.h>
41
42 #include "smbus_if.h"
43
44 /*This should be removed if force_pci_map_int supported*/
45 #include <sys/interrupt.h>
46
47 #include <dev/pci/pcireg.h>
48 #include <dev/pci/pcivar.h>
49 #include <pci/intpmreg.h>
50
51 #include "opt_intpm.h"
52
53 static struct _pcsid
54 {
55         u_int32_t type;
56         char    *desc;
57 } pci_ids[] = {
58         { 0x71138086, "Intel 82371AB Power management controller" },
59         { 0x719b8086, "Intel 82443MX Power management controller" },
60 #if 0
61         /* Not a good idea yet, this stops isab0 functioning */
62         { 0x02001166, "ServerWorks OSB4 PCI to ISA Bridge" },
63 #endif
64
65         { 0x00000000, NULL }
66 };
67
68 static int intsmb_probe(device_t);
69 static int intsmb_attach(device_t);
70 static int intsmb_intr(device_t dev);
71 static int intsmb_slvintr(device_t dev);
72 static void  intsmb_alrintr(device_t dev);
73 static int intsmb_callback(device_t dev, int index, void *data);
74 static int intsmb_quick(device_t dev, u_char slave, int how);
75 static int intsmb_sendb(device_t dev, u_char slave, char byte);
76 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
77 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
78 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
79 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
80 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
81 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
82 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
83 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf);
84 static void intsmb_start(device_t dev, u_char cmd, int nointr);
85 static int intsmb_stop(device_t dev);
86 static int intsmb_stop_poll(device_t dev);
87 static int intsmb_free(device_t dev);
88 static int intpm_probe (device_t dev);
89 static int intpm_attach (device_t dev);
90 static void intpm_intr(void *arg);
91
92 static devclass_t intsmb_devclass;
93
94 static device_method_t intpm_methods[] = {
95         /* Device interface */
96         DEVMETHOD(device_probe,         intsmb_probe),
97         DEVMETHOD(device_attach,        intsmb_attach),
98
99         /* Bus interface */
100         DEVMETHOD(bus_print_child,      bus_generic_print_child),
101
102         /* SMBus interface */
103         DEVMETHOD(smbus_callback,       intsmb_callback),
104         DEVMETHOD(smbus_quick,          intsmb_quick),
105         DEVMETHOD(smbus_sendb,          intsmb_sendb),
106         DEVMETHOD(smbus_recvb,          intsmb_recvb),
107         DEVMETHOD(smbus_writeb,         intsmb_writeb),
108         DEVMETHOD(smbus_writew,         intsmb_writew),
109         DEVMETHOD(smbus_readb,          intsmb_readb),
110         DEVMETHOD(smbus_readw,          intsmb_readw),
111         DEVMETHOD(smbus_pcall,          intsmb_pcall),
112         DEVMETHOD(smbus_bwrite,         intsmb_bwrite),
113         DEVMETHOD(smbus_bread,          intsmb_bread),
114
115         { 0, 0 }
116 };
117
118 struct intpm_pci_softc {
119         bus_space_tag_t         smbst;
120         bus_space_handle_t      smbsh;
121         bus_space_tag_t         pmst;
122         bus_space_handle_t      pmsh;
123         device_t                smbus;
124 };
125
126
127 struct intsmb_softc {
128         struct intpm_pci_softc  *pci_sc;
129         bus_space_tag_t         st;
130         bus_space_handle_t      sh;
131         device_t                smbus;
132         int                     isbusy;
133 };
134
135 static driver_t intpm_driver = {
136         "intsmb",
137         intpm_methods,
138         sizeof(struct intsmb_softc),
139 };
140
141 static devclass_t intpm_devclass;
142
143 static device_method_t intpm_pci_methods[] = {
144         DEVMETHOD(device_probe,         intpm_probe),
145         DEVMETHOD(device_attach,        intpm_attach),
146
147         { 0, 0 }
148 };
149
150 static driver_t intpm_pci_driver = {
151         "intpm",
152         intpm_pci_methods,
153         sizeof(struct intpm_pci_softc)
154 };
155
156 static int
157 intsmb_probe(device_t dev)
158 {
159         struct intsmb_softc *sc = device_get_softc(dev);
160
161         sc->smbus = device_add_child(dev, "smbus", -1);
162         if (!sc->smbus)
163                 return (EINVAL);    /* XXX don't know what to return else */
164         device_set_desc(dev, "Intel PIIX4 SMBUS Interface");
165
166         return (BUS_PROBE_DEFAULT); /* XXX don't know what to return else */
167 }
168 static int
169 intsmb_attach(device_t dev)
170 {
171         struct intsmb_softc *sc = device_get_softc(dev);
172
173         sc->pci_sc = device_get_softc(device_get_parent(dev));
174         sc->isbusy = 0;
175         sc->sh = sc->pci_sc->smbsh;
176         sc->st = sc->pci_sc->smbst;
177         sc->pci_sc->smbus = dev;
178         device_probe_and_attach(sc->smbus);
179 #ifdef ENABLE_ALART
180         /*Enable Arart*/
181         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
182             PIIX4_SMBSLVCNT_ALTEN);
183 #endif
184         return (0);
185 }
186
187 static int
188 intsmb_callback(device_t dev, int index, void *data)
189 {
190         int error = 0;
191         intrmask_t s;
192
193         s = splnet();
194         switch (index) {
195         case SMB_REQUEST_BUS:
196                 break;
197         case SMB_RELEASE_BUS:
198                 break;
199         default:
200                 error = EINVAL;
201         }
202         splx(s);
203
204         return (error);
205 }
206
207 /* Counterpart of smbtx_smb_free(). */
208 static int
209 intsmb_free(device_t dev)
210 {
211         struct intsmb_softc *sc = device_get_softc(dev);
212         intrmask_t s;
213
214         if ((bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS) &
215             PIIX4_SMBHSTSTAT_BUSY) ||
216 #ifdef ENABLE_ALART
217             (bus_space_read_1(sc->st, sc->sh, PIIX4_SMBSLVSTS) & 
218             PIIX4_SMBSLVSTS_BUSY) ||
219 #endif
220             sc->isbusy)
221                 return (EBUSY);
222         s = splhigh();
223         sc->isbusy = 1;
224         /* Disable Interrupt in slave part. */
225 #ifndef ENABLE_ALART
226         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT, 0);
227 #endif
228         /* Reset INTR Flag to prepare INTR. */
229         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTSTS,
230             (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
231             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL));
232         splx(s);
233         return (0);
234 }
235
236 static int
237 intsmb_intr(device_t dev)
238 {
239         struct intsmb_softc *sc = device_get_softc(dev);
240         int status;
241
242         status = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS);
243         if (status & PIIX4_SMBHSTSTAT_BUSY)
244                 return (1);
245
246         if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
247             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) {
248                 int tmp;
249
250                 tmp = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
251                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCNT,
252                     tmp & ~PIIX4_SMBHSTCNT_INTREN);
253                 if (sc->isbusy) {
254                         sc->isbusy = 0;
255                         wakeup(sc);
256                 }
257                 return (0);
258         }
259         return (1); /* Not Completed */
260 }
261
262 static int
263 intsmb_slvintr(device_t dev)
264 {
265         struct intsmb_softc *sc = device_get_softc(dev);
266         int status, retval;
267
268         retval = 1;
269         status = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBSLVSTS);
270         if (status & PIIX4_SMBSLVSTS_BUSY)
271                 return (retval);
272         if (status & PIIX4_SMBSLVSTS_ALART) {
273                 intsmb_alrintr(dev);
274                 retval = 0;
275         } else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2
276                 | PIIX4_SMBSLVSTS_SDW1)) {
277                 retval = 0;
278         }
279
280         /* Reset Status Register */
281         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVSTS,
282             PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 |
283             PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV);
284         return (retval);
285 }
286
287 static void
288 intsmb_alrintr(device_t dev)
289 {
290         struct intsmb_softc *sc = device_get_softc(dev);
291         int slvcnt;
292 #ifdef ENABLE_ALART
293         int error;
294 #endif
295
296         /* Stop generating INTR from ALART. */
297         slvcnt = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBSLVCNT);
298 #ifdef ENABLE_ALART
299         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
300             slvcnt & ~PIIX4_SMBSLVCNT_ALTEN);
301 #endif
302         DELAY(5);
303
304         /* Ask bus who asserted it and then ask it what's the matter. */
305 #ifdef ENABLE_ALART
306         error = intsmb_free(dev);
307         if (!error) {
308                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
309                     SMBALTRESP | LSB);
310                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BYTE, 1);
311                 if (!(error = intsmb_stop_poll(dev))) {
312                         u_int8_t addr;
313
314                         addr = bus_space_read_1(sc->st, sc->sh,
315                             PIIX4_SMBHSTDAT0);
316                         printf("ALART_RESPONSE: 0x%x\n", addr);
317                 }
318         } else
319                 printf("ERROR\n");
320
321         /* Re-enable INTR from ALART. */
322         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
323             slvcnt | PIIX4_SMBSLVCNT_ALTEN);
324         DELAY(5);
325 #endif
326 }
327
328 static void
329 intsmb_start(device_t dev, unsigned char cmd, int nointr)
330 {
331         struct intsmb_softc *sc = device_get_softc(dev);
332         unsigned char tmp;
333
334         tmp = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
335         tmp &= 0xe0;
336         tmp |= cmd;
337         tmp |= PIIX4_SMBHSTCNT_START;
338
339         /* While not in autoconfiguration enable interrupts. */
340         if (!cold || !nointr)
341                 tmp |= PIIX4_SMBHSTCNT_INTREN;
342         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCNT, tmp);
343 }
344
345 /*
346  * Polling Code.
347  *
348  * Polling is not encouraged because it requires waiting for the
349  * device if it is busy.
350  * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use
351  * polling code then.
352  */
353 static int
354 intsmb_stop_poll(device_t dev)
355 {
356         struct intsmb_softc *sc = device_get_softc(dev);
357         int error, i;
358         int tmp;
359
360         /*
361          *  In smbtx driver, Simply waiting.
362          *  This loops 100-200 times.
363          */
364         for (i = 0; i < 0x7fff; i++)
365                 if (bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS) &
366                     PIIX4_SMBHSTSTAT_BUSY)
367                         break;
368
369         for (i = 0; i < 0x7fff; i++) {
370                 int status;
371
372                 status = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS);
373                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
374                         sc->isbusy = 0;
375                         error = (status & PIIX4_SMBHSTSTAT_ERR) ? EIO :
376                             (status & PIIX4_SMBHSTSTAT_BUSC) ? EBUSY : 
377                             (status & PIIX4_SMBHSTSTAT_FAIL) ? EIO : 0;
378                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
379                                 printf("unknown cause why?");
380                         return (error);
381                 }
382         }
383
384         sc->isbusy = 0;
385         tmp = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
386         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCNT, 
387             tmp & ~PIIX4_SMBHSTCNT_INTREN);
388         return (EIO);
389 }
390
391 /*
392  * Wait for completion and return result.
393  */
394 static int
395 intsmb_stop(device_t dev)
396 {
397         struct intsmb_softc *sc = device_get_softc(dev);
398         int error;
399         intrmask_t s;
400
401         if (cold) {
402                 /* So that it can use device during device probe on SMBus. */
403                 error = intsmb_stop_poll(dev);
404                 return (error);
405         }
406
407         if (!tsleep(sc, (PWAIT) | PCATCH, "SMBWAI", hz/8)) {
408                 int status;
409
410                 status = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTSTS);
411                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
412                         error = (status & PIIX4_SMBHSTSTAT_ERR) ? EIO :
413                             (status & PIIX4_SMBHSTSTAT_BUSC) ? EBUSY : 
414                             (status & PIIX4_SMBHSTSTAT_FAIL) ? EIO : 0;
415                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
416                                 printf("intsmb%d: unknown cause why?\n",
417                                     device_get_unit(dev));
418 #ifdef ENABLE_ALART
419                         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
420                             PIIX4_SMBSLVCNT_ALTEN);
421 #endif
422                         return (error);
423                 }
424         }
425
426         /* Timeout Procedure. */
427         s = splhigh();
428         sc->isbusy = 0;
429
430         /* Re-enable supressed interrupt from slave part. */
431         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBSLVCNT,
432             PIIX4_SMBSLVCNT_ALTEN);
433         splx(s);
434         return (EIO);
435 }
436
437 static int
438 intsmb_quick(device_t dev, u_char slave, int how)
439 {
440         struct intsmb_softc *sc = device_get_softc(dev);
441         int error = 0;
442         u_char data;
443
444         data = slave;
445
446         /* Quick command is part of Address, I think. */
447         switch(how) {
448         case SMB_QWRITE:
449                 data &= ~LSB;
450                 break;
451         case SMB_QREAD:
452                 data |= LSB;
453                 break;
454         default:
455                 error = EINVAL;
456         }
457         if (!error) {
458                 error = intsmb_free(dev);
459                 if (!error) {
460                         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
461                             data);
462                         intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_QUICK, 0);
463                         error = intsmb_stop(dev);
464                 }
465         }
466
467         return (error);
468 }
469
470 static int
471 intsmb_sendb(device_t dev, u_char slave, char byte)
472 {
473         struct intsmb_softc *sc = device_get_softc(dev);
474         int error;
475
476         error = intsmb_free(dev);
477         if (!error) {
478                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
479                     slave & ~LSB);
480                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, byte);
481                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
482                 error = intsmb_stop(dev);
483         }
484         return (error);
485 }
486
487 static int
488 intsmb_recvb(device_t dev, u_char slave, char *byte)
489 {
490         struct intsmb_softc *sc = device_get_softc(dev);
491         int error;
492
493         error = intsmb_free(dev);
494         if (!error) {
495                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD, slave | LSB);
496                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
497                 if (!(error = intsmb_stop(dev))) {
498 #ifdef RECV_IS_IN_CMD
499                         /*
500                          * Linux SMBus stuff also troubles
501                          * Because Intel's datasheet does not make clear.
502                          */
503                         *byte = bus_space_read_1(sc->st, sc->sh,
504                             PIIX4_SMBHSTCMD);
505 #else
506                         *byte = bus_space_read_1(sc->st, sc->sh, 
507                             PIIX4_SMBHSTDAT0);
508 #endif
509                 }
510         }
511         return (error);
512 }
513
514 static int
515 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
516 {
517         struct intsmb_softc *sc = device_get_softc(dev);
518         int error;
519
520         error = intsmb_free(dev);
521         if (!error) {
522                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
523                     slave & ~LSB);
524                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
525                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0, byte);
526                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
527                 error = intsmb_stop(dev);
528         }
529         return (error);
530 }
531
532 static int
533 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
534 {
535         struct intsmb_softc *sc = device_get_softc(dev);
536         int error;
537
538         error = intsmb_free(dev);
539         if (!error) {
540                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
541                     slave & ~LSB);
542                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
543                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0, 
544                     word & 0xff);
545                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT1, 
546                     (word >> 8) & 0xff);
547                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
548                 error = intsmb_stop(dev);
549         }
550         return (error);
551 }
552
553 static int
554 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
555 {
556         struct intsmb_softc *sc = device_get_softc(dev);
557         int error;
558
559         error = intsmb_free(dev);
560         if (!error) {
561                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD, slave | LSB);
562                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
563                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
564                 if (!(error = intsmb_stop(dev)))
565                         *byte = bus_space_read_1(sc->st, sc->sh,
566                             PIIX4_SMBHSTDAT0);
567         }
568         return (error);
569 }
570 static int
571 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
572 {
573         struct intsmb_softc *sc = device_get_softc(dev);
574         int error;
575
576         error = intsmb_free(dev);
577         if (!error) {
578                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD, slave | LSB);
579                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
580                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
581                 if (!(error = intsmb_stop(dev))) {
582                         *word = bus_space_read_1(sc->st, sc->sh,
583                             PIIX4_SMBHSTDAT0);
584                         *word |= bus_space_read_1(sc->st, sc->sh,
585                             PIIX4_SMBHSTDAT1) << 8;
586                 }
587         }
588         return (error);
589 }
590
591 /*
592  * Data sheet claims that it implements all function, but also claims
593  * that it implements 7 function and not mention PCALL. So I don't know
594  * whether it will work.
595  */
596 static int
597 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
598 {
599 #ifdef PROCCALL_TEST
600         struct intsmb_softc *sc = device_get_softc(dev);
601         int error;
602
603         error = intsmb_free(dev);
604         if (!error) {
605                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
606                     slave & ~LSB);
607                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
608                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0,
609                     sdata & 0xff);
610                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT1,
611                     (sdata & 0xff) >> 8);
612                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
613         }
614         if (!(error = intsmb_stop(dev))) {
615                 *rdata = bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0);
616                 *rdata |= bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTDAT1) <<
617                     8;
618         }
619         return (error);
620 #else
621         return (0);
622 #endif
623 }
624
625 static int
626 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
627 {
628         struct intsmb_softc *sc = device_get_softc(dev);
629         int error, i;
630
631         error = intsmb_free(dev);
632         if (count > SMBBLOCKTRANS_MAX || count == 0)
633                 error = SMB_EINVAL;
634         if (!error) {
635                 /* Reset internal array index. */
636                 bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
637
638                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD,
639                     slave & ~LSB);
640                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
641                 for (i = 0; i < count; i++)
642                         bus_space_write_1(sc->st, sc->sh, PIIX4_SMBBLKDAT,
643                             buf[i]);
644                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0, count);
645                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
646                 error = intsmb_stop(dev);
647         }
648         return (error);
649 }
650
651 static int
652 intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
653 {
654         struct intsmb_softc *sc = device_get_softc(dev);
655         int error, i;
656         u_char data, nread;
657
658         error = intsmb_free(dev);
659         if (*count > SMBBLOCKTRANS_MAX || *count == 0)
660                 error = SMB_EINVAL;
661         if (!error) {
662                 /* Reset internal array index. */
663                 bus_space_read_1(sc->st, sc->sh, PIIX4_SMBHSTCNT);
664
665                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTADD, slave | LSB);
666                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTCMD, cmd);
667                 bus_space_write_1(sc->st, sc->sh, PIIX4_SMBHSTDAT0, *count);
668                 intsmb_start(dev, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
669                 error = intsmb_stop(dev);
670                 if (!error) {
671                         nread= bus_space_read_1(sc->st, sc->sh,
672                             PIIX4_SMBHSTDAT0);
673                         if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) {
674                                 for (i = 0; i < nread; i++) {
675                                         data = bus_space_read_1(sc->st, sc->sh, 
676                                             PIIX4_SMBBLKDAT);
677                                         if (i < *count)
678                                                 buf[i] = data;
679                                 }
680                                 *count = nread;
681                         } else {
682                                 error = EIO;
683                         }
684                 }
685         }
686         return (error);
687 }
688
689 DRIVER_MODULE(intsmb, intpm, intpm_driver, intsmb_devclass, 0, 0);
690
691 static int
692 intpm_attach(device_t dev)
693 {
694         struct intpm_pci_softc *sc;
695         struct resource *res;
696         device_t smbinterface;
697         void *ih;
698         char *str;
699         int error, rid, value;
700         int unit = device_get_unit(dev);
701
702         sc = device_get_softc(dev);
703         if (sc == NULL)
704                 return (ENOMEM);
705
706         rid = PCI_BASE_ADDR_SMB;
707         res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
708         if (res == NULL) {
709                 device_printf(dev, "Could not allocate Bus space\n");
710                 return (ENXIO);
711         }
712         sc->smbst = rman_get_bustag(res);
713         sc->smbsh = rman_get_bushandle(res);
714
715 #ifdef __i386__
716         device_printf(dev, "%s %lx\n", (sc->smbst == I386_BUS_SPACE_IO) ?
717             "I/O mapped" : "Memory", rman_get_start(res));
718 #endif
719
720 #ifndef NO_CHANGE_PCICONF
721         pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
722         pci_write_config(dev, PCI_HST_CFG_SMB,
723             PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
724 #endif
725         value = pci_read_config(dev, PCI_HST_CFG_SMB, 1);
726         switch (value & 0xe) {
727         case PCI_INTR_SMB_SMI:
728                 str = "SMI";
729                 break;
730         case PCI_INTR_SMB_IRQ9:
731                 str = "IRQ 9";
732                 break;
733         default:
734                 str = "BOGUS";
735         }
736         device_printf(dev, "intr %s %s ", str,
737             (value & 1) ? "enabled" : "disabled");
738         value = pci_read_config(dev, PCI_REVID_SMB, 1);
739         printf("revision %d\n", value);
740
741         /* Install interrupt handler. */
742         rid = 0;
743         res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 9, 9, 1,
744             RF_SHAREABLE | RF_ACTIVE);
745         if (res == NULL) {
746                 device_printf(dev, "could not allocate irq");
747                 return (ENOMEM);
748         }
749         error = bus_setup_intr(dev, res, INTR_TYPE_MISC, intpm_intr, sc, &ih);
750         if (error) {
751                 device_printf(dev, "Failed to map intr\n");
752                 return (error);
753         }
754         smbinterface = device_add_child(dev, "intsmb", unit);
755         if (!smbinterface)
756                 printf("intsmb%d: could not add SMBus device\n", unit);
757         device_probe_and_attach(smbinterface);
758
759         value = pci_read_config(dev, PCI_BASE_ADDR_PM, 4);
760         printf("intpm%d: PM %s %x \n", unit,
761             (value & 1) ? "I/O mapped" : "Memory", value & 0xfffe);
762         return (0);
763 }
764
765 static int
766 intpm_probe(device_t dev)
767 {
768         struct _pcsid *ep = pci_ids;
769         uint32_t device_id = pci_get_devid(dev);
770
771         while (ep->type && ep->type != device_id)
772                 ++ep;
773         if (ep->desc != NULL) {
774                 device_set_desc(dev, ep->desc);
775                 bus_set_resource(dev, SYS_RES_IRQ, 0, 9, 1); /* XXX setup intr resource */
776                 return (BUS_PROBE_DEFAULT);
777         } else {
778                 return (ENXIO);
779         }
780 }
781
782 static void
783 intpm_intr(void *arg)
784 {
785         struct intpm_pci_softc *sc = arg;
786
787         intsmb_intr(sc->smbus);
788         intsmb_slvintr(sc->smbus);
789 }
790
791 DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
792 DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0);
793 MODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
794 MODULE_VERSION(intpm, 1);