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