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