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