nfsmb.c revision 163459
1#include <sys/cdefs.h> 2__FBSDID("$FreeBSD: head/sys/pci/nfsmb.c 163459 2006-10-17 10:26:11Z ru $"); 3 4#include <sys/param.h> 5#include <sys/kernel.h> 6#include <sys/systm.h> 7#include <sys/module.h> 8#include <sys/bus.h> 9#include <sys/uio.h> 10 11#include <machine/bus.h> 12#include <machine/resource.h> 13#include <sys/rman.h> 14 15#include <dev/pci/pcivar.h> 16#include <dev/pci/pcireg.h> 17 18#include <dev/iicbus/iiconf.h> 19#include <dev/smbus/smbconf.h> 20#include "smbus_if.h" 21 22#define NFSMB_DEBUG(x) if (nfsmb_debug) (x) 23 24#ifdef DEBUG 25static int nfsmb_debug = 1; 26#else 27static int nfsmb_debug = 0; 28#endif 29 30/* NVIDIA nForce2/3/4 MCP */ 31#define NFSMB_VENDORID_NVIDIA 0x10de 32#define NFSMB_DEVICEID_NF2_SMB 0x0064 33#define NFSMB_DEVICEID_NF2_ULTRA_SMB 0x0084 34#define NFSMB_DEVICEID_NF3_PRO150_SMB 0x00d4 35#define NFSMB_DEVICEID_NF3_250GB_SMB 0x00e4 36#define NFSMB_DEVICEID_NF4_SMB 0x0052 37#define NFSMB_DEVICEID_NF4_04_SMB 0x0034 38#define NFSMB_DEVICEID_NF4_51_SMB 0x0264 39#define NFSMB_DEVICEID_NF4_55_SMB 0x0368 40 41/* PCI Configuration space registers */ 42#define NF2PCI_SMBASE_1 PCIR_BAR(4) 43#define NF2PCI_SMBASE_2 PCIR_BAR(5) 44 45/* 46 * ACPI 3.0, Chapter 12, SMBus Host Controller Interface. 47 */ 48#define SMB_PRTCL 0x00 /* protocol */ 49#define SMB_STS 0x01 /* status */ 50#define SMB_ADDR 0x02 /* address */ 51#define SMB_CMD 0x03 /* command */ 52#define SMB_DATA 0x04 /* 32 data registers */ 53#define SMB_BCNT 0x24 /* number of data bytes */ 54#define SMB_ALRM_A 0x25 /* alarm address */ 55#define SMB_ALRM_D 0x26 /* 2 bytes alarm data */ 56 57#define SMB_STS_DONE 0x80 58#define SMB_STS_ALRM 0x40 59#define SMB_STS_RES 0x20 60#define SMB_STS_STATUS 0x1f 61#define SMB_STS_OK 0x00 /* OK */ 62#define SMB_STS_UF 0x07 /* Unknown Failure */ 63#define SMB_STS_DANA 0x10 /* Device Address Not Acknowledged */ 64#define SMB_STS_DED 0x11 /* Device Error Detected */ 65#define SMB_STS_DCAD 0x12 /* Device Command Access Denied */ 66#define SMB_STS_UE 0x13 /* Unknown Error */ 67#define SMB_STS_DAD 0x17 /* Device Access Denied */ 68#define SMB_STS_T 0x18 /* Timeout */ 69#define SMB_STS_HUP 0x19 /* Host Unsupported Protocol */ 70#define SMB_STS_B 0x1A /* Busy */ 71#define SMB_STS_PEC 0x1F /* PEC (CRC-8) Error */ 72 73#define SMB_PRTCL_WRITE 0x00 74#define SMB_PRTCL_READ 0x01 75#define SMB_PRTCL_QUICK 0x02 76#define SMB_PRTCL_BYTE 0x04 77#define SMB_PRTCL_BYTE_DATA 0x06 78#define SMB_PRTCL_WORD_DATA 0x08 79#define SMB_PRTCL_BLOCK_DATA 0x0a 80#define SMB_PRTCL_PROC_CALL 0x0c 81#define SMB_PRTCL_BLOCK_PROC_CALL 0x0d 82#define SMB_PRTCL_PEC 0x80 83 84struct nfsmb_softc { 85 int rid; 86 struct resource *res; 87 bus_space_tag_t smbst; 88 bus_space_handle_t smbsh; 89 90 device_t smbus; 91 device_t subdev; 92}; 93 94#define NFSMB_SMBINB(nfsmb, register) \ 95 (bus_space_read_1(nfsmb->smbst, nfsmb->smbsh, register)) 96#define NFSMB_SMBOUTB(nfsmb, register, value) \ 97 (bus_space_write_1(nfsmb->smbst, nfsmb->smbsh, register, value)) 98 99static int 100nfsmbsub_probe(device_t dev) 101{ 102 103 device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 104 return (BUS_PROBE_DEFAULT); 105} 106 107static int 108nfsmb_probe(device_t dev) 109{ 110 u_int16_t vid; 111 u_int16_t did; 112 113 vid = pci_get_vendor(dev); 114 did = pci_get_device(dev); 115 116 if (vid == NFSMB_VENDORID_NVIDIA) { 117 switch(did) { 118 case NFSMB_DEVICEID_NF2_SMB: 119 case NFSMB_DEVICEID_NF2_ULTRA_SMB: 120 case NFSMB_DEVICEID_NF3_PRO150_SMB: 121 case NFSMB_DEVICEID_NF3_250GB_SMB: 122 case NFSMB_DEVICEID_NF4_SMB: 123 case NFSMB_DEVICEID_NF4_04_SMB: 124 case NFSMB_DEVICEID_NF4_51_SMB: 125 case NFSMB_DEVICEID_NF4_55_SMB: 126 device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 127 return (BUS_PROBE_DEFAULT); 128 } 129 } 130 131 return (ENXIO); 132} 133 134static int 135nfsmbsub_attach(device_t dev) 136{ 137 device_t parent; 138 struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev); 139 140 parent = device_get_parent(dev); 141 142 nfsmbsub_sc->rid = NF2PCI_SMBASE_2; 143 144 nfsmbsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT, 145 &nfsmbsub_sc->rid, RF_ACTIVE); 146 if (nfsmbsub_sc->res == NULL) { 147 /* Older incarnations of the device used non-standard BARs. */ 148 nfsmbsub_sc->rid = 0x54; 149 nfsmbsub_sc->res = bus_alloc_resource_any(parent, 150 SYS_RES_IOPORT, &nfsmbsub_sc->rid, RF_ACTIVE); 151 if (nfsmbsub_sc->res == NULL) { 152 device_printf(dev, "could not map i/o space\n"); 153 return (ENXIO); 154 } 155 } 156 nfsmbsub_sc->smbst = rman_get_bustag(nfsmbsub_sc->res); 157 nfsmbsub_sc->smbsh = rman_get_bushandle(nfsmbsub_sc->res); 158 159 nfsmbsub_sc->smbus = device_add_child(dev, "smbus", -1); 160 if (nfsmbsub_sc->smbus == NULL) 161 return (EINVAL); 162 163 bus_generic_attach(dev); 164 165 return (0); 166} 167 168static int 169nfsmb_attach(device_t dev) 170{ 171 struct nfsmb_softc *nfsmb_sc = device_get_softc(dev); 172 173 /* Allocate I/O space */ 174 nfsmb_sc->rid = NF2PCI_SMBASE_1; 175 176 nfsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 177 &nfsmb_sc->rid, RF_ACTIVE); 178 179 if (nfsmb_sc->res == NULL) { 180 /* Older incarnations of the device used non-standard BARs. */ 181 nfsmb_sc->rid = 0x50; 182 nfsmb_sc->res = bus_alloc_resource_any(dev, 183 SYS_RES_IOPORT, &nfsmb_sc->rid, RF_ACTIVE); 184 if (nfsmb_sc->res == NULL) { 185 device_printf(dev, "could not map i/o space\n"); 186 return (ENXIO); 187 } 188 } 189 190 nfsmb_sc->smbst = rman_get_bustag(nfsmb_sc->res); 191 nfsmb_sc->smbsh = rman_get_bushandle(nfsmb_sc->res); 192 193 /* Allocate a new smbus device */ 194 nfsmb_sc->smbus = device_add_child(dev, "smbus", -1); 195 if (!nfsmb_sc->smbus) 196 return (EINVAL); 197 198 nfsmb_sc->subdev = NULL; 199 switch (pci_get_device(dev)) { 200 case NFSMB_DEVICEID_NF2_SMB: 201 case NFSMB_DEVICEID_NF2_ULTRA_SMB: 202 case NFSMB_DEVICEID_NF3_PRO150_SMB: 203 case NFSMB_DEVICEID_NF3_250GB_SMB: 204 case NFSMB_DEVICEID_NF4_SMB: 205 case NFSMB_DEVICEID_NF4_04_SMB: 206 case NFSMB_DEVICEID_NF4_51_SMB: 207 case NFSMB_DEVICEID_NF4_55_SMB: 208 /* Trying to add secondary device as slave */ 209 nfsmb_sc->subdev = device_add_child(dev, "nfsmb", -1); 210 if (!nfsmb_sc->subdev) 211 return (EINVAL); 212 break; 213 default: 214 break; 215 } 216 217 bus_generic_attach(dev); 218 219 return (0); 220} 221 222static int 223nfsmbsub_detach(device_t dev) 224{ 225 device_t parent; 226 struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev); 227 228 parent = device_get_parent(dev); 229 230 if (nfsmbsub_sc->smbus) { 231 device_delete_child(dev, nfsmbsub_sc->smbus); 232 nfsmbsub_sc->smbus = NULL; 233 } 234 if (nfsmbsub_sc->res) { 235 bus_release_resource(parent, SYS_RES_IOPORT, nfsmbsub_sc->rid, 236 nfsmbsub_sc->res); 237 nfsmbsub_sc->res = NULL; 238 } 239 return (0); 240} 241 242static int 243nfsmb_detach(device_t dev) 244{ 245 struct nfsmb_softc *nfsmb_sc = device_get_softc(dev); 246 247 if (nfsmb_sc->subdev) { 248 device_delete_child(dev, nfsmb_sc->subdev); 249 nfsmb_sc->subdev = NULL; 250 } 251 252 if (nfsmb_sc->smbus) { 253 device_delete_child(dev, nfsmb_sc->smbus); 254 nfsmb_sc->smbus = NULL; 255 } 256 257 if (nfsmb_sc->res) { 258 bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid, 259 nfsmb_sc->res); 260 nfsmb_sc->res = NULL; 261 } 262 263 return (0); 264} 265 266static int 267nfsmb_callback(device_t dev, int index, void *data) 268{ 269 int error = 0; 270 271 switch (index) { 272 case SMB_REQUEST_BUS: 273 case SMB_RELEASE_BUS: 274 break; 275 default: 276 error = EINVAL; 277 } 278 279 return (error); 280} 281 282static int 283nfsmb_wait(struct nfsmb_softc *sc) 284{ 285 u_char sts; 286 int error, count; 287 288 if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0) 289 { 290 count = 10000; 291 do { 292 DELAY(500); 293 } while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--); 294 if (count == 0) 295 return (SMB_ETIMEOUT); 296 } 297 298 sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS; 299 NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts)); 300 301 switch (sts) { 302 case SMB_STS_OK: 303 error = SMB_ENOERR; 304 break; 305 case SMB_STS_DANA: 306 error = SMB_ENOACK; 307 break; 308 case SMB_STS_B: 309 error = SMB_EBUSY; 310 break; 311 case SMB_STS_T: 312 error = SMB_ETIMEOUT; 313 break; 314 case SMB_STS_DCAD: 315 case SMB_STS_DAD: 316 case SMB_STS_HUP: 317 error = SMB_ENOTSUPP; 318 break; 319 default: 320 error = SMB_EBUSERR; 321 break; 322 } 323 324 return (error); 325} 326 327static int 328nfsmb_quick(device_t dev, u_char slave, int how) 329{ 330 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 331 u_char protocol; 332 int error; 333 334 protocol = SMB_PRTCL_QUICK; 335 336 switch (how) { 337 case SMB_QWRITE: 338 protocol |= SMB_PRTCL_WRITE; 339 NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave)); 340 break; 341 case SMB_QREAD: 342 protocol |= SMB_PRTCL_READ; 343 NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave)); 344 break; 345 default: 346 panic("%s: unknown QUICK command (%x)!", __func__, how); 347 } 348 349 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 350 NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol); 351 352 error = nfsmb_wait(sc); 353 354 NFSMB_DEBUG(printf(", error=0x%x\n", error)); 355 356 return (error); 357} 358 359static int 360nfsmb_sendb(device_t dev, u_char slave, char byte) 361{ 362 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 363 int error; 364 365 NFSMB_SMBOUTB(sc, SMB_CMD, byte); 366 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 367 NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE); 368 369 error = nfsmb_wait(sc); 370 371 NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 372 373 return (error); 374} 375 376static int 377nfsmb_recvb(device_t dev, u_char slave, char *byte) 378{ 379 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 380 int error; 381 382 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 383 NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE); 384 385 if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 386 *byte = NFSMB_SMBINB(sc, SMB_DATA); 387 388 NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 389 390 return (error); 391} 392 393static int 394nfsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 395{ 396 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 397 int error; 398 399 NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 400 NFSMB_SMBOUTB(sc, SMB_DATA, byte); 401 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 402 NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA); 403 404 error = nfsmb_wait(sc); 405 406 NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 407 408 return (error); 409} 410 411static int 412nfsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 413{ 414 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 415 int error; 416 417 NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 418 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 419 NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA); 420 421 if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 422 *byte = NFSMB_SMBINB(sc, SMB_DATA); 423 424 NFSMB_DEBUG(printf("nfsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, (unsigned char)*byte, error)); 425 426 return (error); 427} 428 429static int 430nfsmb_writew(device_t dev, u_char slave, char cmd, short word) 431{ 432 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 433 int error; 434 435 NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 436 NFSMB_SMBOUTB(sc, SMB_DATA, word); 437 NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8); 438 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 439 NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA); 440 441 error = nfsmb_wait(sc); 442 443 NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 444 445 return (error); 446} 447 448static int 449nfsmb_readw(device_t dev, u_char slave, char cmd, short *word) 450{ 451 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 452 int error; 453 454 NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 455 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 456 NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA); 457 458 if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 459 *word = NFSMB_SMBINB(sc, SMB_DATA) | 460 (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8); 461 462 NFSMB_DEBUG(printf("nfsmb: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, (unsigned short)*word, error)); 463 464 return (error); 465} 466 467static int 468nfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 469{ 470 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 471 u_char i; 472 int error; 473 474 if (count < 1 || count > 32) 475 return (SMB_EINVAL); 476 NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 477 NFSMB_SMBOUTB(sc, SMB_BCNT, count); 478 for (i = 0; i < count; i++) 479 NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]); 480 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 481 NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA); 482 483 error = nfsmb_wait(sc); 484 485 NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 486 487 return (error); 488} 489 490static int 491nfsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 492{ 493 struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 494 u_char data, len, i; 495 int error; 496 497 if (*count < 1 || *count > 32) 498 return (SMB_EINVAL); 499 NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 500 NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 501 NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA); 502 503 if ((error = nfsmb_wait(sc)) == SMB_ENOERR) { 504 len = NFSMB_SMBINB(sc, SMB_BCNT); 505 for (i = 0; i < len; i++) { 506 data = NFSMB_SMBINB(sc, SMB_DATA + i); 507 if (i < *count) 508 buf[i] = data; 509 } 510 *count = len; 511 } 512 513 NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 514 515 return (error); 516} 517 518static device_method_t nfsmb_methods[] = { 519 /* Device interface */ 520 DEVMETHOD(device_probe, nfsmb_probe), 521 DEVMETHOD(device_attach, nfsmb_attach), 522 DEVMETHOD(device_detach, nfsmb_detach), 523 524 /* SMBus interface */ 525 DEVMETHOD(smbus_callback, nfsmb_callback), 526 DEVMETHOD(smbus_quick, nfsmb_quick), 527 DEVMETHOD(smbus_sendb, nfsmb_sendb), 528 DEVMETHOD(smbus_recvb, nfsmb_recvb), 529 DEVMETHOD(smbus_writeb, nfsmb_writeb), 530 DEVMETHOD(smbus_readb, nfsmb_readb), 531 DEVMETHOD(smbus_writew, nfsmb_writew), 532 DEVMETHOD(smbus_readw, nfsmb_readw), 533 DEVMETHOD(smbus_bwrite, nfsmb_bwrite), 534 DEVMETHOD(smbus_bread, nfsmb_bread), 535 536 { 0, 0 } 537}; 538 539static device_method_t nfsmbsub_methods[] = { 540 /* Device interface */ 541 DEVMETHOD(device_probe, nfsmbsub_probe), 542 DEVMETHOD(device_attach, nfsmbsub_attach), 543 DEVMETHOD(device_detach, nfsmbsub_detach), 544 545 /* SMBus interface */ 546 DEVMETHOD(smbus_callback, nfsmb_callback), 547 DEVMETHOD(smbus_quick, nfsmb_quick), 548 DEVMETHOD(smbus_sendb, nfsmb_sendb), 549 DEVMETHOD(smbus_recvb, nfsmb_recvb), 550 DEVMETHOD(smbus_writeb, nfsmb_writeb), 551 DEVMETHOD(smbus_readb, nfsmb_readb), 552 DEVMETHOD(smbus_writew, nfsmb_writew), 553 DEVMETHOD(smbus_readw, nfsmb_readw), 554 DEVMETHOD(smbus_bwrite, nfsmb_bwrite), 555 DEVMETHOD(smbus_bread, nfsmb_bread), 556 557 { 0, 0 } 558}; 559 560static devclass_t nfsmb_devclass; 561 562static driver_t nfsmb_driver = { 563 "nfsmb", 564 nfsmb_methods, 565 sizeof(struct nfsmb_softc), 566}; 567 568static driver_t nfsmbsub_driver = { 569 "nfsmb", 570 nfsmbsub_methods, 571 sizeof(struct nfsmb_softc), 572}; 573 574DRIVER_MODULE(nfsmb, pci, nfsmb_driver, nfsmb_devclass, 0, 0); 575DRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, nfsmb_devclass, 0, 0); 576DRIVER_MODULE(smbus, nfsmb, smbus_driver, smbus_devclass, 0, 0); 577 578MODULE_DEPEND(nfsmb, pci, 1, 1, 1); 579MODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 580MODULE_VERSION(nfsmb, 1); 581