intpm.c revision 197128
133965Sjdp/*- 2218822Sdim * Copyright (c) 1998, 1999 Takanori Watanabe 389857Sobrien * All rights reserved. 433965Sjdp * 533965Sjdp * Redistribution and use in source and binary forms, with or without 633965Sjdp * modification, are permitted provided that the following conditions 733965Sjdp * are met: 833965Sjdp * 1. Redistributions of source code must retain the above copyright 933965Sjdp * notice, this list of conditions and the following disclaimer. 1033965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1133965Sjdp * notice, this list of conditions and the following disclaimer in the 1233965Sjdp * documentation and/or other materials provided with the distribution. 1333965Sjdp * 1433965Sjdp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1533965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1733965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1833965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19218822Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2033965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2233965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2333965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2433965Sjdp * SUCH DAMAGE. 2533965Sjdp */ 2633965Sjdp 2733965Sjdp#include <sys/cdefs.h> 2833965Sjdp__FBSDID("$FreeBSD: head/sys/pci/intpm.c 197128 2009-09-12 18:24:31Z avg $"); 2933965Sjdp 3033965Sjdp#include <sys/param.h> 3133965Sjdp#include <sys/systm.h> 3233965Sjdp#include <sys/bus.h> 3333965Sjdp#include <sys/kernel.h> 3433965Sjdp#include <sys/lock.h> 3533965Sjdp#include <sys/module.h> 3633965Sjdp#include <sys/mutex.h> 3733965Sjdp#include <sys/rman.h> 3833965Sjdp#include <machine/bus.h> 3989857Sobrien#include <dev/smbus/smbconf.h> 4089857Sobrien 4189857Sobrien#include "smbus_if.h" 4289857Sobrien 4333965Sjdp#include <dev/pci/pcireg.h> 4433965Sjdp#include <dev/pci/pcivar.h> 45218822Sdim#include <pci/intpmreg.h> 4633965Sjdp 4733965Sjdp#include "opt_intpm.h" 4833965Sjdp 4933965Sjdpstruct intsmb_softc { 5033965Sjdp 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 65static int intsmb_probe(device_t); 66static int intsmb_attach(device_t); 67static int intsmb_detach(device_t); 68static int intsmb_intr(struct intsmb_softc *sc); 69static int intsmb_slvintr(struct intsmb_softc *sc); 70static void intsmb_alrintr(struct intsmb_softc *sc); 71static int intsmb_callback(device_t dev, int index, void *data); 72static int intsmb_quick(device_t dev, u_char slave, int how); 73static int intsmb_sendb(device_t dev, u_char slave, char byte); 74static int intsmb_recvb(device_t dev, u_char slave, char *byte); 75static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 76static int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 77static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 78static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 79static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 80static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 81static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf); 82static void intsmb_start(struct intsmb_softc *sc, u_char cmd, int nointr); 83static int intsmb_stop(struct intsmb_softc *sc); 84static int intsmb_stop_poll(struct intsmb_softc *sc); 85static int intsmb_free(struct intsmb_softc *sc); 86static void intsmb_rawintr(void *arg); 87 88static int 89intsmb_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 112static int 113intsmb_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) 171 goto no_intr; 172 173 if (intr != PCI_INTR_SMB_IRQ9 && intr != PCI_INTR_SMB_IRQ_PCI) { 174 device_printf(dev, "Unsupported interrupt mode\n"); 175 error = ENXIO; 176 goto fail; 177 } 178 179 /* Force IRQ 9. */ 180 rid = 0; 181 if (sc->cfg_irq9) 182 bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1); 183 184 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 185 RF_SHAREABLE | RF_ACTIVE); 186 if (sc->irq_res == NULL) { 187 device_printf(dev, "Could not allocate irq\n"); 188 error = ENXIO; 189 goto fail; 190 } 191 192 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 193 NULL, intsmb_rawintr, sc, &sc->irq_hand); 194 if (error) { 195 device_printf(dev, "Failed to map intr\n"); 196 goto fail; 197 } 198 199no_intr: 200 sc->isbusy = 0; 201 sc->smbus = device_add_child(dev, "smbus", -1); 202 if (sc->smbus == NULL) { 203 error = ENXIO; 204 goto fail; 205 } 206 error = device_probe_and_attach(sc->smbus); 207 if (error) 208 goto fail; 209 210#ifdef ENABLE_ALART 211 /* Enable Arart */ 212 bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN); 213#endif 214 return (0); 215 216fail: 217 intsmb_detach(dev); 218 return (error); 219} 220 221static int 222intsmb_detach(device_t dev) 223{ 224 struct intsmb_softc *sc = device_get_softc(dev); 225 int error; 226 227 error = bus_generic_detach(dev); 228 if (error) 229 return (error); 230 231 if (sc->smbus) 232 device_delete_child(dev, sc->smbus); 233 if (sc->irq_hand) 234 bus_teardown_intr(dev, sc->irq_res, sc->irq_hand); 235 if (sc->irq_res) 236 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); 237 if (sc->io_res) 238 bus_release_resource(dev, SYS_RES_IOPORT, PCI_BASE_ADDR_SMB, 239 sc->io_res); 240 mtx_destroy(&sc->lock); 241 return (0); 242} 243 244static void 245intsmb_rawintr(void *arg) 246{ 247 struct intsmb_softc *sc = arg; 248 249 INTSMB_LOCK(sc); 250 intsmb_intr(sc); 251 intsmb_slvintr(sc); 252 INTSMB_UNLOCK(sc); 253} 254 255static int 256intsmb_callback(device_t dev, int index, void *data) 257{ 258 int error = 0; 259 260 switch (index) { 261 case SMB_REQUEST_BUS: 262 break; 263 case SMB_RELEASE_BUS: 264 break; 265 default: 266 error = EINVAL; 267 } 268 269 return (error); 270} 271 272/* Counterpart of smbtx_smb_free(). */ 273static int 274intsmb_free(struct intsmb_softc *sc) 275{ 276 277 INTSMB_LOCK_ASSERT(sc); 278 if ((bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & PIIX4_SMBHSTSTAT_BUSY) || 279#ifdef ENABLE_ALART 280 (bus_read_1(sc->io_res, PIIX4_SMBSLVSTS) & PIIX4_SMBSLVSTS_BUSY) || 281#endif 282 sc->isbusy) 283 return (SMB_EBUSY); 284 285 sc->isbusy = 1; 286 /* Disable Interrupt in slave part. */ 287#ifndef ENABLE_ALART 288 bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 0); 289#endif 290 /* Reset INTR Flag to prepare INTR. */ 291 bus_write_1(sc->io_res, PIIX4_SMBHSTSTS, 292 PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR | 293 PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL); 294 return (0); 295} 296 297static int 298intsmb_intr(struct intsmb_softc *sc) 299{ 300 int status, tmp; 301 302 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); 303 if (status & PIIX4_SMBHSTSTAT_BUSY) 304 return (1); 305 306 if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR | 307 PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) { 308 309 tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 310 bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, 311 tmp & ~PIIX4_SMBHSTCNT_INTREN); 312 if (sc->isbusy) { 313 sc->isbusy = 0; 314 wakeup(sc); 315 } 316 return (0); 317 } 318 return (1); /* Not Completed */ 319} 320 321static int 322intsmb_slvintr(struct intsmb_softc *sc) 323{ 324 int status; 325 326 status = bus_read_1(sc->io_res, PIIX4_SMBSLVSTS); 327 if (status & PIIX4_SMBSLVSTS_BUSY) 328 return (1); 329 if (status & PIIX4_SMBSLVSTS_ALART) 330 intsmb_alrintr(sc); 331 else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 332 | PIIX4_SMBSLVSTS_SDW1)) { 333 } 334 335 /* Reset Status Register */ 336 bus_write_1(sc->io_res, PIIX4_SMBSLVSTS, 337 PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 | 338 PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV); 339 return (0); 340} 341 342static void 343intsmb_alrintr(struct intsmb_softc *sc) 344{ 345 int slvcnt; 346#ifdef ENABLE_ALART 347 int error; 348 uint8_t addr; 349#endif 350 351 /* Stop generating INTR from ALART. */ 352 slvcnt = bus_read_1(sc->io_res, PIIX4_SMBSLVCNT); 353#ifdef ENABLE_ALART 354 bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 355 slvcnt & ~PIIX4_SMBSLVCNT_ALTEN); 356#endif 357 DELAY(5); 358 359 /* Ask bus who asserted it and then ask it what's the matter. */ 360#ifdef ENABLE_ALART 361 error = intsmb_free(sc); 362 if (error) 363 return; 364 365 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, SMBALTRESP | LSB); 366 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 1); 367 error = intsmb_stop_poll(sc); 368 if (error) 369 device_printf(sc->dev, "ALART: ERROR\n"); 370 else { 371 addr = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 372 device_printf(sc->dev, "ALART_RESPONSE: 0x%x\n", addr); 373 } 374 375 /* Re-enable INTR from ALART. */ 376 bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 377 slvcnt | PIIX4_SMBSLVCNT_ALTEN); 378 DELAY(5); 379#endif 380} 381 382static void 383intsmb_start(struct intsmb_softc *sc, unsigned char cmd, int nointr) 384{ 385 unsigned char tmp; 386 387 INTSMB_LOCK_ASSERT(sc); 388 tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 389 tmp &= 0xe0; 390 tmp |= cmd; 391 tmp |= PIIX4_SMBHSTCNT_START; 392 393 /* While not in autoconfiguration enable interrupts. */ 394 if (!sc->poll && !cold && !nointr) 395 tmp |= PIIX4_SMBHSTCNT_INTREN; 396 bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp); 397} 398 399static int 400intsmb_error(device_t dev, int status) 401{ 402 int error = 0; 403 404 if (status & PIIX4_SMBHSTSTAT_ERR) 405 error |= SMB_EBUSERR; 406 if (status & PIIX4_SMBHSTSTAT_BUSC) 407 error |= SMB_ECOLLI; 408 if (status & PIIX4_SMBHSTSTAT_FAIL) 409 error |= SMB_ENOACK; 410 411 if (error != 0 && bootverbose) 412 device_printf(dev, "error = %d, status = %#x\n", error, status); 413 414 return (error); 415} 416 417/* 418 * Polling Code. 419 * 420 * Polling is not encouraged because it requires waiting for the 421 * device if it is busy. 422 * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use 423 * polling code then. 424 */ 425static int 426intsmb_stop_poll(struct intsmb_softc *sc) 427{ 428 int error, i, status, tmp; 429 430 INTSMB_LOCK_ASSERT(sc); 431 432 /* First, wait for busy to be set. */ 433 for (i = 0; i < 0x7fff; i++) 434 if (bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & 435 PIIX4_SMBHSTSTAT_BUSY) 436 break; 437 438 /* Wait for busy to clear. */ 439 for (i = 0; i < 0x7fff; i++) { 440 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); 441 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) { 442 sc->isbusy = 0; 443 error = intsmb_error(sc->dev, status); 444 return (error); 445 } 446 } 447 448 /* Timed out waiting for busy to clear. */ 449 sc->isbusy = 0; 450 tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 451 bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp & ~PIIX4_SMBHSTCNT_INTREN); 452 return (SMB_ETIMEOUT); 453} 454 455/* 456 * Wait for completion and return result. 457 */ 458static int 459intsmb_stop(struct intsmb_softc *sc) 460{ 461 int error, status; 462 463 INTSMB_LOCK_ASSERT(sc); 464 465 if (sc->poll || cold) 466 /* So that it can use device during device probe on SMBus. */ 467 return (intsmb_stop_poll(sc)); 468 469 error = msleep(sc, &sc->lock, PWAIT | PCATCH, "SMBWAI", hz / 8); 470 if (error == 0) { 471 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); 472 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) { 473 error = intsmb_error(sc->dev, status); 474 if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR)) 475 device_printf(sc->dev, "unknown cause why?\n"); 476#ifdef ENABLE_ALART 477 bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 478 PIIX4_SMBSLVCNT_ALTEN); 479#endif 480 return (error); 481 } 482 } 483 484 /* Timeout Procedure. */ 485 sc->isbusy = 0; 486 487 /* Re-enable supressed interrupt from slave part. */ 488 bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN); 489 if (error == EWOULDBLOCK) 490 return (SMB_ETIMEOUT); 491 else 492 return (SMB_EABORT); 493} 494 495static int 496intsmb_quick(device_t dev, u_char slave, int how) 497{ 498 struct intsmb_softc *sc = device_get_softc(dev); 499 int error; 500 u_char data; 501 502 data = slave; 503 504 /* Quick command is part of Address, I think. */ 505 switch(how) { 506 case SMB_QWRITE: 507 data &= ~LSB; 508 break; 509 case SMB_QREAD: 510 data |= LSB; 511 break; 512 default: 513 return (EINVAL); 514 } 515 516 INTSMB_LOCK(sc); 517 error = intsmb_free(sc); 518 if (error) { 519 INTSMB_UNLOCK(sc); 520 return (error); 521 } 522 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, data); 523 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_QUICK, 0); 524 error = intsmb_stop(sc); 525 INTSMB_UNLOCK(sc); 526 return (error); 527} 528 529static int 530intsmb_sendb(device_t dev, u_char slave, char byte) 531{ 532 struct intsmb_softc *sc = device_get_softc(dev); 533 int error; 534 535 INTSMB_LOCK(sc); 536 error = intsmb_free(sc); 537 if (error) { 538 INTSMB_UNLOCK(sc); 539 return (error); 540 } 541 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 542 bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, byte); 543 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0); 544 error = intsmb_stop(sc); 545 INTSMB_UNLOCK(sc); 546 return (error); 547} 548 549static int 550intsmb_recvb(device_t dev, u_char slave, char *byte) 551{ 552 struct intsmb_softc *sc = device_get_softc(dev); 553 int error; 554 555 INTSMB_LOCK(sc); 556 error = intsmb_free(sc); 557 if (error) { 558 INTSMB_UNLOCK(sc); 559 return (error); 560 } 561 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); 562 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0); 563 error = intsmb_stop(sc); 564 if (error == 0) { 565#ifdef RECV_IS_IN_CMD 566 /* 567 * Linux SMBus stuff also troubles 568 * Because Intel's datasheet does not make clear. 569 */ 570 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTCMD); 571#else 572 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 573#endif 574 } 575 INTSMB_UNLOCK(sc); 576 return (error); 577} 578 579static int 580intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 581{ 582 struct intsmb_softc *sc = device_get_softc(dev); 583 int error; 584 585 INTSMB_LOCK(sc); 586 error = intsmb_free(sc); 587 if (error) { 588 INTSMB_UNLOCK(sc); 589 return (error); 590 } 591 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 592 bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 593 bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, byte); 594 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0); 595 error = intsmb_stop(sc); 596 INTSMB_UNLOCK(sc); 597 return (error); 598} 599 600static int 601intsmb_writew(device_t dev, u_char slave, char cmd, short word) 602{ 603 struct intsmb_softc *sc = device_get_softc(dev); 604 int error; 605 606 INTSMB_LOCK(sc); 607 error = intsmb_free(sc); 608 if (error) { 609 INTSMB_UNLOCK(sc); 610 return (error); 611 } 612 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 613 bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 614 bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, word & 0xff); 615 bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (word >> 8) & 0xff); 616 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); 617 error = intsmb_stop(sc); 618 INTSMB_UNLOCK(sc); 619 return (error); 620} 621 622static int 623intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 624{ 625 struct intsmb_softc *sc = device_get_softc(dev); 626 int error; 627 628 INTSMB_LOCK(sc); 629 error = intsmb_free(sc); 630 if (error) { 631 INTSMB_UNLOCK(sc); 632 return (error); 633 } 634 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); 635 bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 636 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0); 637 error = intsmb_stop(sc); 638 if (error == 0) 639 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 640 INTSMB_UNLOCK(sc); 641 return (error); 642} 643 644static int 645intsmb_readw(device_t dev, u_char slave, char cmd, short *word) 646{ 647 struct intsmb_softc *sc = device_get_softc(dev); 648 int error; 649 650 INTSMB_LOCK(sc); 651 error = intsmb_free(sc); 652 if (error) { 653 INTSMB_UNLOCK(sc); 654 return (error); 655 } 656 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); 657 bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 658 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); 659 error = intsmb_stop(sc); 660 if (error == 0) { 661 *word = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 662 *word |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8; 663 } 664 INTSMB_UNLOCK(sc); 665 return (error); 666} 667 668/* 669 * Data sheet claims that it implements all function, but also claims 670 * that it implements 7 function and not mention PCALL. So I don't know 671 * whether it will work. 672 */ 673static int 674intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 675{ 676#ifdef PROCCALL_TEST 677 struct intsmb_softc *sc = device_get_softc(dev); 678 int error; 679 680 INTSMB_LOCK(sc); 681 error = intsmb_free(sc); 682 if (error) { 683 INTSMB_UNLOCK(sc); 684 return (error); 685 } 686 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 687 bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 688 bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, sdata & 0xff); 689 bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (sdata & 0xff) >> 8); 690 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); 691 error = intsmb_stop(sc); 692 if (error == 0) { 693 *rdata = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 694 *rdata |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8; 695 } 696 INTSMB_UNLOCK(sc); 697 return (error); 698#else 699 return (SMB_ENOTSUPP); 700#endif 701} 702 703static int 704intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 705{ 706 struct intsmb_softc *sc = device_get_softc(dev); 707 int error, i; 708 709 if (count > SMBBLOCKTRANS_MAX || count == 0) 710 return (SMB_EINVAL); 711 712 INTSMB_LOCK(sc); 713 error = intsmb_free(sc); 714 if (error) { 715 INTSMB_UNLOCK(sc); 716 return (error); 717 } 718 719 /* Reset internal array index. */ 720 bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 721 722 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); 723 bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 724 for (i = 0; i < count; i++) 725 bus_write_1(sc->io_res, PIIX4_SMBBLKDAT, buf[i]); 726 bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, count); 727 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0); 728 error = intsmb_stop(sc); 729 INTSMB_UNLOCK(sc); 730 return (error); 731} 732 733static int 734intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 735{ 736 struct intsmb_softc *sc = device_get_softc(dev); 737 int error, i; 738 u_char data, nread; 739 740 if (*count > SMBBLOCKTRANS_MAX || *count == 0) 741 return (SMB_EINVAL); 742 743 INTSMB_LOCK(sc); 744 error = intsmb_free(sc); 745 if (error) { 746 INTSMB_UNLOCK(sc); 747 return (error); 748 } 749 750 /* Reset internal array index. */ 751 bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); 752 753 bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); 754 bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); 755 bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, *count); 756 intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0); 757 error = intsmb_stop(sc); 758 if (error == 0) { 759 nread = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); 760 if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) { 761 for (i = 0; i < nread; i++) { 762 data = bus_read_1(sc->io_res, PIIX4_SMBBLKDAT); 763 if (i < *count) 764 buf[i] = data; 765 } 766 *count = nread; 767 } else 768 error = EIO; 769 } 770 INTSMB_UNLOCK(sc); 771 return (error); 772} 773 774static devclass_t intsmb_devclass; 775 776static device_method_t intsmb_methods[] = { 777 /* Device interface */ 778 DEVMETHOD(device_probe, intsmb_probe), 779 DEVMETHOD(device_attach, intsmb_attach), 780 DEVMETHOD(device_detach, intsmb_detach), 781 782 /* Bus interface */ 783 DEVMETHOD(bus_print_child, bus_generic_print_child), 784 785 /* SMBus interface */ 786 DEVMETHOD(smbus_callback, intsmb_callback), 787 DEVMETHOD(smbus_quick, intsmb_quick), 788 DEVMETHOD(smbus_sendb, intsmb_sendb), 789 DEVMETHOD(smbus_recvb, intsmb_recvb), 790 DEVMETHOD(smbus_writeb, intsmb_writeb), 791 DEVMETHOD(smbus_writew, intsmb_writew), 792 DEVMETHOD(smbus_readb, intsmb_readb), 793 DEVMETHOD(smbus_readw, intsmb_readw), 794 DEVMETHOD(smbus_pcall, intsmb_pcall), 795 DEVMETHOD(smbus_bwrite, intsmb_bwrite), 796 DEVMETHOD(smbus_bread, intsmb_bread), 797 798 { 0, 0 } 799}; 800 801static driver_t intsmb_driver = { 802 "intsmb", 803 intsmb_methods, 804 sizeof(struct intsmb_softc), 805}; 806 807DRIVER_MODULE(intsmb, pci, intsmb_driver, intsmb_devclass, 0, 0); 808DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0); 809MODULE_DEPEND(intsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 810MODULE_VERSION(intsmb, 1); 811