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