1 /*- 2 * ichsmb.c 3 * 4 * Author: Archie Cobbs <archie@freebsd.org> 5 * Copyright (c) 2000 Whistle Communications, Inc. 6 * All rights reserved. 7 * 8 * Subject to the following obligations and disclaimer of warranty, use and 9 * redistribution of this software, in source or object code forms, with or 10 * without modifications are expressly permitted by Whistle Communications; 11 * provided, however, that: 12 * 1. Any and all reproductions of the source or object code must include the 13 * copyright notice above and the following disclaimer of warranties; and 14 * 2. No rights are granted, in any manner or form, to use Whistle 15 * Communications, Inc. trademarks, including the mark "WHISTLE 16 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 17 * such appears in the above copyright notice or in the software. 18 * 19 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 20 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 21 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 22 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 24 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 25 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 26 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 27 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 28 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 29 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 30 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 31 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 35 * OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 /* 42 * Support for the SMBus controller logical device which is part of the 43 * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips. 44 * 45 * This driver assumes that the generic SMBus code will ensure that 46 * at most one process at a time calls into the SMBus methods below. 47 */ 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/kernel.h> 52 #include <sys/errno.h> 53 #include <sys/lock.h> 54 #include <sys/module.h> 55 #include <sys/mutex.h> 56 #include <sys/syslog.h> 57 #include <sys/bus.h> 58 59 #include <machine/bus.h> 60 #include <sys/rman.h> 61 #include <machine/resource.h> 62 63 #include <dev/smbus/smbconf.h> 64 65 #include <dev/ichsmb/ichsmb_var.h> 66 #include <dev/ichsmb/ichsmb_reg.h> 67 68 /* 69 * Enable debugging by defining ICHSMB_DEBUG to a non-zero value. 70 */ 71 #define ICHSMB_DEBUG 0 72 #if ICHSMB_DEBUG != 0 && defined(__CC_SUPPORTS___FUNC__) 73 #define DBG(fmt, args...) \ 74 do { printf("%s: " fmt, __func__ , ## args); } while (0) 75 #else 76 #define DBG(fmt, args...) do { } while (0) 77 #endif 78 79 /* 80 * Our child device driver name 81 */ 82 #define DRIVER_SMBUS "smbus" 83 84 /* 85 * Internal functions 86 */ 87 static int ichsmb_wait(sc_p sc); 88 89 /******************************************************************** 90 BUS-INDEPENDENT BUS METHODS 91 ********************************************************************/ 92 93 /* 94 * Handle probe-time duties that are independent of the bus 95 * our device lives on. 96 */ 97 int 98 ichsmb_probe(device_t dev) 99 { 100 return (BUS_PROBE_DEFAULT); 101 } 102 103 /* 104 * Handle attach-time duties that are independent of the bus 105 * our device lives on. 106 */ 107 int 108 ichsmb_attach(device_t dev) 109 { 110 const sc_p sc = device_get_softc(dev); 111 int error; 112 113 /* Create mutex */ 114 mtx_init(&sc->mutex, device_get_nameunit(dev), "ichsmb", MTX_DEF); 115 116 /* Add child: an instance of the "smbus" device */ 117 if ((sc->smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) { 118 device_printf(dev, "no \"%s\" child found\n", DRIVER_SMBUS); 119 error = ENXIO; 120 goto fail; 121 } 122 123 /* Clear interrupt conditions */ 124 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, 0xff); 125 126 /* Set up interrupt handler */ 127 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, 128 NULL, ichsmb_device_intr, sc, &sc->irq_handle); 129 if (error != 0) { 130 device_printf(dev, "can't setup irq\n"); 131 goto fail; 132 } 133 134 /* Attach "smbus" child */ 135 if ((error = bus_generic_attach(dev)) != 0) { 136 device_printf(dev, "failed to attach child: %d\n", error); 137 goto fail; 138 } 139 140 return (0); 141 142 fail: 143 mtx_destroy(&sc->mutex); 144 return (error); 145 } 146 147 /******************************************************************** 148 SMBUS METHODS 149 ********************************************************************/ 150 151 int 152 ichsmb_callback(device_t dev, int index, void *data) 153 { 154 int smb_error = 0; 155 156 DBG("index=%d how=%d\n", index, data ? *(int *)data : -1); 157 switch (index) { 158 case SMB_REQUEST_BUS: 159 break; 160 case SMB_RELEASE_BUS: 161 break; 162 default: 163 smb_error = SMB_EABORT; /* XXX */ 164 break; 165 } 166 DBG("smb_error=%d\n", smb_error); 167 return (smb_error); 168 } 169 170 int 171 ichsmb_quick(device_t dev, u_char slave, int how) 172 { 173 const sc_p sc = device_get_softc(dev); 174 int smb_error; 175 176 DBG("slave=0x%02x how=%d\n", slave, how); 177 KASSERT(sc->ich_cmd == -1, 178 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 179 switch (how) { 180 case SMB_QREAD: 181 case SMB_QWRITE: 182 mtx_lock(&sc->mutex); 183 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK; 184 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 185 (slave << 1) | (how == SMB_QREAD ? 186 ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE)); 187 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 188 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 189 smb_error = ichsmb_wait(sc); 190 mtx_unlock(&sc->mutex); 191 break; 192 default: 193 smb_error = SMB_ENOTSUPP; 194 } 195 DBG("smb_error=%d\n", smb_error); 196 return (smb_error); 197 } 198 199 int 200 ichsmb_sendb(device_t dev, u_char slave, char byte) 201 { 202 const sc_p sc = device_get_softc(dev); 203 int smb_error; 204 205 DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte); 206 KASSERT(sc->ich_cmd == -1, 207 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 208 mtx_lock(&sc->mutex); 209 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 210 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 211 (slave << 1) | ICH_XMIT_SLVA_WRITE); 212 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, byte); 213 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 214 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 215 smb_error = ichsmb_wait(sc); 216 mtx_unlock(&sc->mutex); 217 DBG("smb_error=%d\n", smb_error); 218 return (smb_error); 219 } 220 221 int 222 ichsmb_recvb(device_t dev, u_char slave, char *byte) 223 { 224 const sc_p sc = device_get_softc(dev); 225 int smb_error; 226 227 DBG("slave=0x%02x\n", slave); 228 KASSERT(sc->ich_cmd == -1, 229 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 230 mtx_lock(&sc->mutex); 231 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 232 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 233 (slave << 1) | ICH_XMIT_SLVA_READ); 234 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 235 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 236 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 237 *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); 238 mtx_unlock(&sc->mutex); 239 DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 240 return (smb_error); 241 } 242 243 int 244 ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 245 { 246 const sc_p sc = device_get_softc(dev); 247 int smb_error; 248 249 DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n", 250 slave, (u_char)cmd, (u_char)byte); 251 KASSERT(sc->ich_cmd == -1, 252 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 253 mtx_lock(&sc->mutex); 254 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 255 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 256 (slave << 1) | ICH_XMIT_SLVA_WRITE); 257 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 258 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, byte); 259 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 260 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 261 smb_error = ichsmb_wait(sc); 262 mtx_unlock(&sc->mutex); 263 DBG("smb_error=%d\n", smb_error); 264 return (smb_error); 265 } 266 267 int 268 ichsmb_writew(device_t dev, u_char slave, char cmd, short word) 269 { 270 const sc_p sc = device_get_softc(dev); 271 int smb_error; 272 273 DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n", 274 slave, (u_char)cmd, (u_int16_t)word); 275 KASSERT(sc->ich_cmd == -1, 276 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 277 mtx_lock(&sc->mutex); 278 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 279 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 280 (slave << 1) | ICH_XMIT_SLVA_WRITE); 281 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 282 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, word & 0xff); 283 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, word >> 8); 284 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 285 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 286 smb_error = ichsmb_wait(sc); 287 mtx_unlock(&sc->mutex); 288 DBG("smb_error=%d\n", smb_error); 289 return (smb_error); 290 } 291 292 int 293 ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 294 { 295 const sc_p sc = device_get_softc(dev); 296 int smb_error; 297 298 DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 299 KASSERT(sc->ich_cmd == -1, 300 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 301 mtx_lock(&sc->mutex); 302 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 303 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 304 (slave << 1) | ICH_XMIT_SLVA_READ); 305 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 306 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 307 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 308 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 309 *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); 310 mtx_unlock(&sc->mutex); 311 DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 312 return (smb_error); 313 } 314 315 int 316 ichsmb_readw(device_t dev, u_char slave, char cmd, short *word) 317 { 318 const sc_p sc = device_get_softc(dev); 319 int smb_error; 320 321 DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 322 KASSERT(sc->ich_cmd == -1, 323 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 324 mtx_lock(&sc->mutex); 325 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 326 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 327 (slave << 1) | ICH_XMIT_SLVA_READ); 328 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 329 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 330 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 331 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 332 *word = (bus_space_read_1(sc->io_bst, 333 sc->io_bsh, ICH_D0) & 0xff) 334 | (bus_space_read_1(sc->io_bst, 335 sc->io_bsh, ICH_D1) << 8); 336 } 337 mtx_unlock(&sc->mutex); 338 DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word); 339 return (smb_error); 340 } 341 342 int 343 ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 344 { 345 const sc_p sc = device_get_softc(dev); 346 int smb_error; 347 348 DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n", 349 slave, (u_char)cmd, (u_int16_t)sdata); 350 KASSERT(sc->ich_cmd == -1, 351 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 352 mtx_lock(&sc->mutex); 353 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL; 354 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 355 (slave << 1) | ICH_XMIT_SLVA_WRITE); 356 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 357 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, sdata & 0xff); 358 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, sdata >> 8); 359 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 360 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 361 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 362 *rdata = (bus_space_read_1(sc->io_bst, 363 sc->io_bsh, ICH_D0) & 0xff) 364 | (bus_space_read_1(sc->io_bst, 365 sc->io_bsh, ICH_D1) << 8); 366 } 367 mtx_unlock(&sc->mutex); 368 DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata); 369 return (smb_error); 370 } 371 372 int 373 ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 374 { 375 const sc_p sc = device_get_softc(dev); 376 int smb_error; 377 378 DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 379 #if ICHSMB_DEBUG 380 #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 381 { 382 u_char *p; 383 384 for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 385 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 386 " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 387 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 388 DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 389 DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 390 } 391 } 392 #undef DISP 393 #endif 394 KASSERT(sc->ich_cmd == -1, 395 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 396 if (count < 1 || count > 32) 397 return (SMB_EINVAL); 398 bcopy(buf, sc->block_data, count); 399 sc->block_count = count; 400 sc->block_index = 1; 401 sc->block_write = 1; 402 403 mtx_lock(&sc->mutex); 404 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 405 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 406 (slave << 1) | ICH_XMIT_SLVA_WRITE); 407 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 408 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); 409 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_BLOCK_DB, buf[0]); 410 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 411 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 412 smb_error = ichsmb_wait(sc); 413 mtx_unlock(&sc->mutex); 414 DBG("smb_error=%d\n", smb_error); 415 return (smb_error); 416 } 417 418 int 419 ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 420 { 421 const sc_p sc = device_get_softc(dev); 422 int smb_error; 423 424 DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 425 KASSERT(sc->ich_cmd == -1, 426 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 427 if (*count < 1 || *count > 32) 428 return (SMB_EINVAL); 429 bzero(sc->block_data, sizeof(sc->block_data)); 430 sc->block_count = 0; 431 sc->block_index = 0; 432 sc->block_write = 0; 433 434 mtx_lock(&sc->mutex); 435 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 436 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 437 (slave << 1) | ICH_XMIT_SLVA_READ); 438 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 439 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, *count); /* XXX? */ 440 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 441 ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 442 if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 443 bcopy(sc->block_data, buf, min(sc->block_count, *count)); 444 *count = sc->block_count; 445 } 446 mtx_unlock(&sc->mutex); 447 DBG("smb_error=%d\n", smb_error); 448 #if ICHSMB_DEBUG 449 #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 450 { 451 u_char *p; 452 453 for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 454 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 455 " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 456 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 457 DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 458 DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 459 } 460 } 461 #undef DISP 462 #endif 463 return (smb_error); 464 } 465 466 /******************************************************************** 467 OTHER FUNCTIONS 468 ********************************************************************/ 469 470 /* 471 * This table describes what interrupts we should ever expect to 472 * see after each ICH command, not including the SMBALERT interrupt. 473 */ 474 static const u_int8_t ichsmb_state_irqs[] = { 475 /* quick */ 476 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 477 /* byte */ 478 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 479 /* byte data */ 480 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 481 /* word data */ 482 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 483 /* process call */ 484 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 485 /* block */ 486 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 487 | ICH_HST_STA_BYTE_DONE_STS), 488 /* i2c read (not used) */ 489 (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 490 | ICH_HST_STA_BYTE_DONE_STS) 491 }; 492 493 /* 494 * Interrupt handler. This handler is bus-independent. Note that our 495 * interrupt may be shared, so we must handle "false" interrupts. 496 */ 497 void 498 ichsmb_device_intr(void *cookie) 499 { 500 const sc_p sc = cookie; 501 const device_t dev = sc->dev; 502 const int maxloops = 16; 503 u_int8_t status; 504 u_int8_t ok_bits; 505 int cmd_index; 506 int count; 507 508 mtx_lock(&sc->mutex); 509 for (count = 0; count < maxloops; count++) { 510 511 /* Get and reset status bits */ 512 status = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA); 513 #if ICHSMB_DEBUG 514 if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY)) 515 || count > 0) { 516 DBG("%d stat=0x%02x\n", count, status); 517 } 518 #endif 519 status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY); 520 if (status == 0) 521 break; 522 523 /* Check for unexpected interrupt */ 524 ok_bits = ICH_HST_STA_SMBALERT_STS; 525 cmd_index = sc->ich_cmd >> 2; 526 if (sc->ich_cmd != -1) { 527 KASSERT(cmd_index < sizeof(ichsmb_state_irqs), 528 ("%s: ich_cmd=%d", device_get_nameunit(dev), 529 sc->ich_cmd)); 530 ok_bits |= ichsmb_state_irqs[cmd_index]; 531 } 532 if ((status & ~ok_bits) != 0) { 533 device_printf(dev, "irq 0x%02x during %d\n", status, 534 cmd_index); 535 bus_space_write_1(sc->io_bst, sc->io_bsh, 536 ICH_HST_STA, (status & ~ok_bits)); 537 continue; 538 } 539 540 /* Handle SMBALERT interrupt */ 541 if (status & ICH_HST_STA_SMBALERT_STS) { 542 static int smbalert_count = 16; 543 if (smbalert_count > 0) { 544 device_printf(dev, "SMBALERT# rec'd\n"); 545 if (--smbalert_count == 0) { 546 device_printf(dev, 547 "not logging anymore\n"); 548 } 549 } 550 } 551 552 /* Check for bus error */ 553 if (status & ICH_HST_STA_BUS_ERR) { 554 sc->smb_error = SMB_ECOLLI; /* XXX SMB_EBUSERR? */ 555 goto finished; 556 } 557 558 /* Check for device error */ 559 if (status & ICH_HST_STA_DEV_ERR) { 560 sc->smb_error = SMB_ENOACK; /* or SMB_ETIMEOUT? */ 561 goto finished; 562 } 563 564 /* Check for byte completion in block transfer */ 565 if (status & ICH_HST_STA_BYTE_DONE_STS) { 566 if (sc->block_write) { 567 if (sc->block_index < sc->block_count) { 568 569 /* Write next byte */ 570 bus_space_write_1(sc->io_bst, 571 sc->io_bsh, ICH_BLOCK_DB, 572 sc->block_data[sc->block_index++]); 573 } 574 } else { 575 576 /* First interrupt, get the count also */ 577 if (sc->block_index == 0) { 578 sc->block_count = bus_space_read_1( 579 sc->io_bst, sc->io_bsh, ICH_D0); 580 } 581 582 /* Get next byte, if any */ 583 if (sc->block_index < sc->block_count) { 584 585 /* Read next byte */ 586 sc->block_data[sc->block_index++] = 587 bus_space_read_1(sc->io_bst, 588 sc->io_bsh, ICH_BLOCK_DB); 589 590 /* Set "LAST_BYTE" bit before reading 591 the last byte of block data */ 592 if (sc->block_index 593 >= sc->block_count - 1) { 594 bus_space_write_1(sc->io_bst, 595 sc->io_bsh, ICH_HST_CNT, 596 ICH_HST_CNT_LAST_BYTE 597 | ICH_HST_CNT_INTREN 598 | sc->ich_cmd); 599 } 600 } 601 } 602 } 603 604 /* Check command completion */ 605 if (status & ICH_HST_STA_INTR) { 606 sc->smb_error = SMB_ENOERR; 607 finished: 608 sc->ich_cmd = -1; 609 bus_space_write_1(sc->io_bst, sc->io_bsh, 610 ICH_HST_STA, status); 611 wakeup(sc); 612 break; 613 } 614 615 /* Clear status bits and try again */ 616 bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, status); 617 } 618 mtx_unlock(&sc->mutex); 619 620 /* Too many loops? */ 621 if (count == maxloops) { 622 device_printf(dev, "interrupt loop, status=0x%02x\n", 623 bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); 624 } 625 } 626 627 /* 628 * Wait for command completion. Assumes mutex is held. 629 * Returns an SMB_* error code. 630 */ 631 static int 632 ichsmb_wait(sc_p sc) 633 { 634 const device_t dev = sc->dev; 635 int error, smb_error; 636 637 KASSERT(sc->ich_cmd != -1, 638 ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 639 mtx_assert(&sc->mutex, MA_OWNED); 640 error = msleep(sc, &sc->mutex, PZERO, "ichsmb", hz / 4); 641 DBG("msleep -> %d\n", error); 642 switch (error) { 643 case 0: 644 smb_error = sc->smb_error; 645 break; 646 case EWOULDBLOCK: 647 device_printf(dev, "device timeout, status=0x%02x\n", 648 bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); 649 sc->ich_cmd = -1; 650 smb_error = SMB_ETIMEOUT; 651 break; 652 default: 653 smb_error = SMB_EABORT; 654 break; 655 } 656 return (smb_error); 657 } 658 659 /* 660 * Release resources associated with device. 661 */ 662 void 663 ichsmb_release_resources(sc_p sc) 664 { 665 const device_t dev = sc->dev; 666 667 if (sc->irq_handle != NULL) { 668 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 669 sc->irq_handle = NULL; 670 } 671 if (sc->irq_res != NULL) { 672 bus_release_resource(dev, 673 SYS_RES_IRQ, sc->irq_rid, sc->irq_res); 674 sc->irq_res = NULL; 675 } 676 if (sc->io_res != NULL) { 677 bus_release_resource(dev, 678 SYS_RES_IOPORT, sc->io_rid, sc->io_res); 679 sc->io_res = NULL; 680 } 681 } 682 683 int 684 ichsmb_detach(device_t dev) 685 { 686 const sc_p sc = device_get_softc(dev); 687 int error; 688 689 error = bus_generic_detach(dev); 690 if (error) 691 return (error); 692 device_delete_child(dev, sc->smb); 693 ichsmb_release_resources(sc); 694 mtx_destroy(&sc->mutex); 695 696 return 0; 697 } 698 699 DRIVER_MODULE(smbus, ichsmb, smbus_driver, smbus_devclass, 0, 0); 700