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